finished food view
This commit is contained in:
parent
52abba1f16
commit
65fbbabec5
@ -1,3 +1,4 @@
|
|||||||
|
from cookbook.models import SearchFields
|
||||||
from django.db import migrations
|
from django.db import migrations
|
||||||
|
|
||||||
|
|
||||||
|
@ -1 +1 @@
|
|||||||
.shake[data-v-8f249282]{-webkit-animation:shake-data-v-8f249282 .82s cubic-bezier(.36,.07,.19,.97) both;animation:shake-data-v-8f249282 .82s cubic-bezier(.36,.07,.19,.97) both;transform:translateZ(0);-webkit-backface-visibility:hidden;backface-visibility:hidden;perspective:1000px}@-webkit-keyframes shake-data-v-8f249282{10%,90%{transform:translate3d(-1px,0,0)}20%,80%{transform:translate3d(2px,0,0)}30%,50%,70%{transform:translate3d(-4px,0,0)}40%,60%{transform:translate3d(4px,0,0)}}@keyframes shake-data-v-8f249282{10%,90%{transform:translate3d(-1px,0,0)}20%,80%{transform:translate3d(2px,0,0)}30%,50%,70%{transform:translate3d(-4px,0,0)}40%,60%{transform:translate3d(4px,0,0)}}
|
.shake[data-v-6aec55e4]{-webkit-animation:shake-data-v-6aec55e4 .82s cubic-bezier(.36,.07,.19,.97) both;animation:shake-data-v-6aec55e4 .82s cubic-bezier(.36,.07,.19,.97) both;transform:translateZ(0);-webkit-backface-visibility:hidden;backface-visibility:hidden;perspective:1000px}@-webkit-keyframes shake-data-v-6aec55e4{10%,90%{transform:translate3d(-1px,0,0)}20%,80%{transform:translate3d(2px,0,0)}30%,50%,70%{transform:translate3d(-4px,0,0)}40%,60%{transform:translate3d(4px,0,0)}}@keyframes shake-data-v-6aec55e4{10%,90%{transform:translate3d(-1px,0,0)}20%,80%{transform:translate3d(2px,0,0)}30%,50%,70%{transform:translate3d(-4px,0,0)}40%,60%{transform:translate3d(4px,0,0)}}
|
@ -1 +1 @@
|
|||||||
.shake[data-v-8f249282]{-webkit-animation:shake-data-v-8f249282 .82s cubic-bezier(.36,.07,.19,.97) both;animation:shake-data-v-8f249282 .82s cubic-bezier(.36,.07,.19,.97) both;transform:translateZ(0);-webkit-backface-visibility:hidden;backface-visibility:hidden;perspective:1000px}@-webkit-keyframes shake-data-v-8f249282{10%,90%{transform:translate3d(-1px,0,0)}20%,80%{transform:translate3d(2px,0,0)}30%,50%,70%{transform:translate3d(-4px,0,0)}40%,60%{transform:translate3d(4px,0,0)}}@keyframes shake-data-v-8f249282{10%,90%{transform:translate3d(-1px,0,0)}20%,80%{transform:translate3d(2px,0,0)}30%,50%,70%{transform:translate3d(-4px,0,0)}40%,60%{transform:translate3d(4px,0,0)}}
|
.shake[data-v-6aec55e4]{-webkit-animation:shake-data-v-6aec55e4 .82s cubic-bezier(.36,.07,.19,.97) both;animation:shake-data-v-6aec55e4 .82s cubic-bezier(.36,.07,.19,.97) both;transform:translateZ(0);-webkit-backface-visibility:hidden;backface-visibility:hidden;perspective:1000px}@-webkit-keyframes shake-data-v-6aec55e4{10%,90%{transform:translate3d(-1px,0,0)}20%,80%{transform:translate3d(2px,0,0)}30%,50%,70%{transform:translate3d(-4px,0,0)}40%,60%{transform:translate3d(4px,0,0)}}@keyframes shake-data-v-6aec55e4{10%,90%{transform:translate3d(-1px,0,0)}20%,80%{transform:translate3d(2px,0,0)}30%,50%,70%{transform:translate3d(-4px,0,0)}40%,60%{transform:translate3d(4px,0,0)}}
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -242,6 +242,9 @@ class TreeMixin(MergeMixin, FuzzyFilterMixin):
|
|||||||
except (PathOverflow, InvalidMoveToDescendant, InvalidPosition):
|
except (PathOverflow, InvalidMoveToDescendant, InvalidPosition):
|
||||||
content = {'error': True, 'msg': _('An error occurred attempting to move ') + child.name}
|
content = {'error': True, 'msg': _('An error occurred attempting to move ') + child.name}
|
||||||
return Response(content, status=status.HTTP_400_BAD_REQUEST)
|
return Response(content, status=status.HTTP_400_BAD_REQUEST)
|
||||||
|
elif parent == child.id:
|
||||||
|
content = {'error': True, 'msg': _('Cannot move an object to itself!')}
|
||||||
|
return Response(content, status=status.HTTP_403_FORBIDDEN)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
parent = self.model.objects.get(pk=parent, space=self.request.space)
|
parent = self.model.objects.get(pk=parent, space=self.request.space)
|
||||||
|
@ -3,131 +3,52 @@
|
|||||||
<generic-modal-form
|
<generic-modal-form
|
||||||
:model="this_model"
|
:model="this_model"
|
||||||
:action="this_action"
|
:action="this_action"
|
||||||
:item1="foods[5]"
|
:item1="this_item"
|
||||||
:item2="undefined"
|
:item2="this_target"
|
||||||
:show="true"/> <!-- TODO make this based on method -->
|
:show="show_modal"
|
||||||
|
@finish-action="finishAction"/>
|
||||||
<generic-split-lists
|
<generic-split-lists
|
||||||
:list_name="this_model.name"
|
:list_name="this_model.name"
|
||||||
@reset="resetList"
|
@reset="resetList"
|
||||||
@get-list="getFoods"
|
@get-list="getItems"
|
||||||
@item-action="startAction"
|
@item-action="startAction"
|
||||||
>
|
>
|
||||||
<template v-slot:cards-left>
|
<template v-slot:cards-left>
|
||||||
<generic-horizontal-card
|
<generic-horizontal-card
|
||||||
v-for="f in foods" v-bind:key="f.id"
|
v-for="i in items_left" v-bind:key="i.id"
|
||||||
:model=f
|
:item=i
|
||||||
:model_name="this_model.name"
|
:item_type="this_model.name"
|
||||||
:draggable="true"
|
:draggable="true"
|
||||||
:merge="true"
|
:merge="true"
|
||||||
:move="true"
|
:move="true"
|
||||||
@item-action="startAction($event, 'left')"
|
@item-action="startAction($event, 'left')"
|
||||||
>
|
>
|
||||||
|
<!-- foods can also be a recipe, show link to the recipe if it exists -->
|
||||||
<template v-slot:upper-right>
|
<template v-slot:upper-right>
|
||||||
<b-button v-if="f.recipe" v-b-tooltip.hover :title="f.recipe.name"
|
<b-button v-if="i.recipe" v-b-tooltip.hover :title="i.recipe.name"
|
||||||
class=" btn fas fa-book-open p-0 border-0" variant="link" :href="f.recipe.url"/>
|
class=" btn fas fa-book-open p-0 border-0" variant="link" :href="i.recipe.url"/>
|
||||||
</template>
|
</template>
|
||||||
</generic-horizontal-card>
|
</generic-horizontal-card>
|
||||||
</template>
|
</template>
|
||||||
<template v-slot:cards-right>
|
<template v-slot:cards-right>
|
||||||
<generic-horizontal-card v-for="f in foods2" v-bind:key="f.id"
|
<generic-horizontal-card v-for="i in items_right" v-bind:key="i.id"
|
||||||
:model=f
|
:item=i
|
||||||
:model_name="this_model.name"
|
:item_type="this_model.name"
|
||||||
:draggable="true"
|
:draggable="true"
|
||||||
:merge="true"
|
:merge="true"
|
||||||
:move="true"
|
:move="true"
|
||||||
@item-action="startAction($event, 'right')"
|
@item-action="startAction($event, 'right')"
|
||||||
>
|
>
|
||||||
|
<!-- foods can also be a recipe, show link to the recipe if it exists -->
|
||||||
<template v-slot:upper-right>
|
<template v-slot:upper-right>
|
||||||
<b-button v-if="f.recipe" v-b-tooltip.hover :title="f.recipe.name"
|
<b-button v-if="i.recipe" v-b-tooltip.hover :title="i.recipe.name"
|
||||||
class=" btn fas fa-book-open p-0 border-0" variant="link" :href="f.recipe.url"/>
|
class=" btn fas fa-book-open p-0 border-0" variant="link" :href="i.recipe.url"/>
|
||||||
</template>
|
</template>
|
||||||
</generic-horizontal-card>
|
</generic-horizontal-card>
|
||||||
</template>
|
</template>
|
||||||
</generic-split-lists>
|
</generic-split-lists>
|
||||||
|
|
||||||
<!-- TODO Modals can probably be made generic and moved to component -->
|
|
||||||
<!-- edit modal -->
|
|
||||||
<b-modal class="modal"
|
|
||||||
:id="'id_modal_food_edit'"
|
|
||||||
:title="this.$t('Edit_Food')"
|
|
||||||
:ok-title="this.$t('Save')"
|
|
||||||
:cancel-title="this.$t('Cancel')"
|
|
||||||
@ok="saveFood">
|
|
||||||
<form>
|
|
||||||
<label for="id_food_name_edit">{{ this.$t('Name') }}</label>
|
|
||||||
<input class="form-control" type="text" id="id_food_name_edit" v-model="this_item.name">
|
|
||||||
<label for="id_food_description_edit">{{ this.$t('Description') }}</label>
|
|
||||||
<input class="form-control" type="text" id="id_food_description_edit" v-model="this_item.description">
|
|
||||||
<label for="id_food_recipe_edit">{{ this.$t('Recipe') }}</label>
|
|
||||||
<!-- TODO initial selection isn't working and I don't know why -->
|
|
||||||
<generic-multiselect
|
|
||||||
@change="this_item.recipe=$event.val"
|
|
||||||
:initial_selection="[this_item.recipe]"
|
|
||||||
:model="recipe"
|
|
||||||
:multiple="false"
|
|
||||||
:sticky_options="[{'id': null,'name': $t('None')}]"
|
|
||||||
style="flex-grow: 1; flex-shrink: 1; flex-basis: 0"
|
|
||||||
:placeholder="this.$t('Search')">
|
|
||||||
</generic-multiselect>
|
|
||||||
<div class="form-group form-check">
|
|
||||||
<input type="checkbox" class="form-check-input" id="id_food_ignore_edit" v-model="this_item.ignore_shopping">
|
|
||||||
<label class="form-check-label" for="id_food_ignore_edit">{{ this.$t('Ignore_Shopping') }}</label>
|
|
||||||
</div>
|
|
||||||
<label for="id_food_category_edit">{{ this.$t('Shopping_Category') }}</label>
|
|
||||||
<generic-multiselect
|
|
||||||
@change="this_item.supermarket_category=$event.val"
|
|
||||||
:model="models.SHOPPING_CATEGORY"
|
|
||||||
:initial_selection="[this_item.supermarket_category]"
|
|
||||||
search_function="listSupermarketCategorys"
|
|
||||||
:multiple="false"
|
|
||||||
:sticky_options="[{'id': null,'name': $t('None')}]"
|
|
||||||
style="flex-grow: 1; flex-shrink: 1; flex-basis: 0"
|
|
||||||
:placeholder="this.$t('Shopping_Category')">
|
|
||||||
</generic-multiselect>
|
|
||||||
</form>
|
|
||||||
</b-modal>
|
|
||||||
<!-- delete modal -->
|
|
||||||
<b-modal class="modal"
|
|
||||||
:id="'id_modal_food_delete'"
|
|
||||||
:title="this.$t('Delete_Food')"
|
|
||||||
:ok-title="this.$t('Delete')"
|
|
||||||
:cancel-title="this.$t('Cancel')"
|
|
||||||
@ok="deleteThis(this_item.id)">
|
|
||||||
{{this.$t("delete_confimation", {'kw': this_item.name})}}
|
|
||||||
</b-modal>
|
|
||||||
<!-- move modal -->
|
|
||||||
<b-modal class="modal"
|
|
||||||
:id="'id_modal_food_move'"
|
|
||||||
:title="this.$t('Move_Food')"
|
|
||||||
:ok-title="this.$t('Move')"
|
|
||||||
:cancel-title="this.$t('Cancel')"
|
|
||||||
@ok="moveFood(this_item.id, this_item.target.id)">
|
|
||||||
{{ this.$t("move_selection", {'child': this_item.name}) }}
|
|
||||||
<generic-multiselect
|
|
||||||
@change="this_item.target=$event.val"
|
|
||||||
:model="this_model"
|
|
||||||
:multiple="false"
|
|
||||||
:sticky_options="[{'id': 0,'name': $t('Root')}]"
|
|
||||||
style="flex-grow: 1; flex-shrink: 1; flex-basis: 0"
|
|
||||||
>
|
|
||||||
</generic-multiselect>
|
|
||||||
</b-modal>
|
|
||||||
<!-- merge modal -->
|
|
||||||
<b-modal class="modal"
|
|
||||||
:id="'id_modal_food_merge'"
|
|
||||||
:title="this.$t('merge_title', {'type': 'Food'})"
|
|
||||||
:ok-title="this.$t('Merge')"
|
|
||||||
:cancel-title="this.$t('Cancel')"
|
|
||||||
@ok="mergeFood(this_item.id, this_item.target.id)">
|
|
||||||
{{ this.$t("merge_selection", {'source': this_item.name, 'type': this.$t('food')}) }}
|
|
||||||
<generic-multiselect
|
|
||||||
@change="this_item.target=$event.val"
|
|
||||||
:model="this_model"
|
|
||||||
:multiple="false"
|
|
||||||
style="flex-grow: 1; flex-shrink: 1; flex-basis: 0"
|
|
||||||
:placeholder="this.$t('Search')">
|
|
||||||
</generic-multiselect>
|
|
||||||
</b-modal>
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@ -145,90 +66,72 @@ import {StandardToasts} from "@/utils/utils";
|
|||||||
|
|
||||||
import GenericSplitLists from "@/components/GenericSplitLists";
|
import GenericSplitLists from "@/components/GenericSplitLists";
|
||||||
import GenericHorizontalCard from "@/components/GenericHorizontalCard";
|
import GenericHorizontalCard from "@/components/GenericHorizontalCard";
|
||||||
import GenericMultiselect from "@/components/GenericMultiselect";
|
|
||||||
import GenericModalForm from "@/components/Modals/GenericModalForm";
|
import GenericModalForm from "@/components/Modals/GenericModalForm";
|
||||||
|
|
||||||
Vue.use(BootstrapVue)
|
Vue.use(BootstrapVue)
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'FoodListView',
|
name: 'FoodListView', // TODO: make generic name
|
||||||
mixins: [CardMixin, ToastMixin],
|
mixins: [CardMixin, ToastMixin],
|
||||||
components: {GenericHorizontalCard, GenericMultiselect, GenericSplitLists, GenericModalForm},
|
components: {GenericHorizontalCard, GenericSplitLists, GenericModalForm},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
this_model: Models.FOOD, //TODO: mounted method to calcuate
|
items_left: [],
|
||||||
this_action: Actions.UPDATE, //TODO: based on what we are doing
|
items_right: [],
|
||||||
models: Models,
|
|
||||||
foods: [],
|
|
||||||
foods2: [],
|
|
||||||
load_more_left: true,
|
load_more_left: true,
|
||||||
load_more_right: true,
|
load_more_right: true,
|
||||||
blank_item: {
|
this_model: Models.FOOD, //TODO: mounted method to calcuate
|
||||||
'id': undefined,
|
this_action: undefined,
|
||||||
'name': '',
|
this_item: {},
|
||||||
'description': '',
|
this_target: {},
|
||||||
'recipe': null,
|
models: Models,
|
||||||
'recipe_full': undefined,
|
show_modal:false
|
||||||
'ignore_shopping': false,
|
|
||||||
'supermarket_category': undefined,
|
|
||||||
'target': {
|
|
||||||
'id': undefined,
|
|
||||||
'name': ''
|
|
||||||
},
|
|
||||||
},
|
|
||||||
this_item: {
|
|
||||||
'id': undefined,
|
|
||||||
'name': '',
|
|
||||||
'description': '',
|
|
||||||
'recipe': null,
|
|
||||||
'recipe_full': undefined,
|
|
||||||
'ignore_shopping': false,
|
|
||||||
'supermarket_category': undefined,
|
|
||||||
'target': {
|
|
||||||
'id': undefined,
|
|
||||||
'name': ''
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
// TODO should model actions be included with the context menu? the card? a seperate mixin avaible to all?
|
|
||||||
resetList: function(e) {
|
resetList: function(e) {
|
||||||
if (e.column === 'left') {
|
if (e.column === 'left') {
|
||||||
this.foods = []
|
this.items_left = []
|
||||||
} else if (e.column === 'right') {
|
} else if (e.column === 'right') {
|
||||||
this.foods2 = []
|
this.items_right = []
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
startAction: function(e, param) {
|
startAction: function(e, param) {
|
||||||
let source = e?.source ?? this.blank_item
|
let source = e?.source ?? {}
|
||||||
let target = e?.target ?? undefined
|
let target = e?.target ?? undefined
|
||||||
this.this_item = source
|
this.this_item = source
|
||||||
this.this_item.target = target || undefined
|
this.this_target = target
|
||||||
|
|
||||||
switch (e.action) {
|
switch (e.action) {
|
||||||
case 'delete':
|
case 'delete':
|
||||||
this.$bvModal.show('id_modal_food_delete')
|
this.this_action = Actions.DELETE
|
||||||
|
this.show_modal = true
|
||||||
break;
|
break;
|
||||||
case 'new':
|
case 'new':
|
||||||
this.this_item = {...this.blank_item}
|
this.this_action = Actions.CREATE
|
||||||
this.$bvModal.show('id_modal_food_edit')
|
this.show_modal = true
|
||||||
break;
|
break;
|
||||||
case 'edit':
|
case 'edit':
|
||||||
this.$bvModal.show('id_modal_food_edit')
|
this.this_item = e.source
|
||||||
|
this.this_action = Actions.UPDATE
|
||||||
|
this.show_modal = true
|
||||||
break;
|
break;
|
||||||
case 'move':
|
case 'move':
|
||||||
if (target == null) {
|
if (target == null) {
|
||||||
this.$bvModal.show('id_modal_food_move')
|
this.this_item = e.source
|
||||||
|
this.this_action = Actions.MOVE
|
||||||
|
this.show_modal = true
|
||||||
} else {
|
} else {
|
||||||
this.moveFood(source.id, target.id)
|
this.moveThis(source.id, target.id)
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'merge':
|
case 'merge':
|
||||||
if (target == null) {
|
if (target == null) {
|
||||||
this.$bvModal.show('id_modal_food_merge')
|
this.this_item = e.source
|
||||||
|
this.this_action = Actions.MERGE
|
||||||
|
this.show_modal = true
|
||||||
} else {
|
} else {
|
||||||
this.mergeFood(e.source.id, e.target.id)
|
this.mergeThis(e.source.id, e.target.id)
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'get-children':
|
case 'get-children':
|
||||||
@ -247,25 +150,51 @@ export default {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
getFoods: function(params, callback) {
|
finishAction: function(e) {
|
||||||
|
let update = undefined
|
||||||
|
if (e !== 'cancel') {
|
||||||
|
switch(this.this_action) {
|
||||||
|
case Actions.DELETE:
|
||||||
|
this.deleteThis(this.this_item.id)
|
||||||
|
break;
|
||||||
|
case Actions.CREATE:
|
||||||
|
this.saveThis(e.form_data)
|
||||||
|
break;
|
||||||
|
case Actions.UPDATE:
|
||||||
|
update = e.form_data
|
||||||
|
update.id = this.this_item.id
|
||||||
|
this.saveThis(update)
|
||||||
|
break;
|
||||||
|
case Actions.MERGE:
|
||||||
|
this.mergeThis(this.this_item.id, e.form_data.target)
|
||||||
|
break;
|
||||||
|
case Actions.MOVE:
|
||||||
|
this.moveThis(this.this_item.id, e.form_data.target)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.clearState()
|
||||||
|
},
|
||||||
|
getItems: function(params, callback) {
|
||||||
let column = params?.column ?? 'left'
|
let column = params?.column ?? 'left'
|
||||||
|
|
||||||
// TODO: does this need to be a callback?
|
// TODO: does this need to be a callback?
|
||||||
genericAPI(this.this_model, Actions.LIST, params).then((result) => {
|
genericAPI(this.this_model, Actions.LIST, params).then((result) => {
|
||||||
if (result.data.results.length){
|
if (result.data.results.length){
|
||||||
if (column ==='left') {
|
if (column ==='left') {
|
||||||
this.foods = this.foods.concat(result.data.results)
|
// if paginated results are in result.data.results otherwise just result.data
|
||||||
|
this.items_left = this.items_left.concat(result.data?.results ?? result.data)
|
||||||
} else if (column ==='right') {
|
} else if (column ==='right') {
|
||||||
this.foods2 = this.foods2.concat(result.data.results)
|
this.items_right = this.items_right.concat(result.data?.results ?? result.data)
|
||||||
}
|
}
|
||||||
// are the total elements less than the length of the array? if so, stop loading
|
// are the total elements less than the length of the array? if so, stop loading
|
||||||
callback(result.data.count > (column==="left" ? this.foods.length : this.foods2.length))
|
callback(result.data.count > (column==="left" ? this.items_left.length : this.items_right.length))
|
||||||
} else {
|
} else {
|
||||||
callback(false) // stop loading
|
callback(false) // stop loading
|
||||||
console.log('no data returned')
|
console.log('no data returned')
|
||||||
}
|
}
|
||||||
// return true if total objects are still less than the length of the list
|
// return true if total objects are still less than the length of the list
|
||||||
callback(result.data.count < (column==="left" ? this.foods.length : this.foods2.length))
|
// TODO this needs generalized to handle non-paginated data
|
||||||
|
callback(result.data.count < (column==="left" ? this.items_left.length : this.items_right.length))
|
||||||
|
|
||||||
}).catch((err) => {
|
}).catch((err) => {
|
||||||
console.log(err)
|
console.log(err)
|
||||||
@ -275,50 +204,52 @@ export default {
|
|||||||
getThis: function(id, callback){
|
getThis: function(id, callback){
|
||||||
return genericAPI(this.this_model, Actions.FETCH, {'id': id})
|
return genericAPI(this.this_model, Actions.FETCH, {'id': id})
|
||||||
},
|
},
|
||||||
saveFood: function () {
|
saveThis: function (thisItem) {
|
||||||
let food = {...this.this_item}
|
if (!thisItem?.id) { // if there is no item id assume it's a new item
|
||||||
food.supermarket_category = this.this_item.supermarket_category?.id ?? null
|
genericAPI(this.this_model, Actions.CREATE, thisItem).then((result) => {
|
||||||
food.recipe = this.this_item.recipe?.id ?? null
|
// place all new items at the top of the list - could sort instead
|
||||||
if (!food?.id) { // if there is no item id assume it's a new item
|
this.items_left = [result.data].concat(this.items_left)
|
||||||
genericAPI(this.this_model, Actions.CREATE, food).then((result) => {
|
|
||||||
// place all new foods at the top of the list - could sort instead
|
|
||||||
this.foods = [result.data].concat(this.foods)
|
|
||||||
// this creates a deep copy to make sure that columns stay independent
|
// this creates a deep copy to make sure that columns stay independent
|
||||||
if (this.show_split){
|
this.items_right = [{...result.data}].concat(this.items_right)
|
||||||
this.foods2 = [...this.foods]
|
|
||||||
} else {
|
|
||||||
this.foods2 = []
|
|
||||||
}
|
|
||||||
StandardToasts.makeStandardToast(StandardToasts.SUCCESS_CREATE)
|
StandardToasts.makeStandardToast(StandardToasts.SUCCESS_CREATE)
|
||||||
}).catch((err) => {
|
}).catch((err) => {
|
||||||
console.log(err)
|
console.log(err)
|
||||||
StandardToasts.makeStandardToast(StandardToasts.FAIL_CREATE)
|
StandardToasts.makeStandardToast(StandardToasts.FAIL_CREATE)
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
genericAPI(this.this_model, Actions.UPDATE, food).then((result) => {
|
genericAPI(this.this_model, Actions.UPDATE, thisItem).then((result) => {
|
||||||
this.refreshObject(food.id)
|
this.refreshThis(thisItem.id)
|
||||||
StandardToasts.makeStandardToast(StandardToasts.SUCCESS_UPDATE)
|
StandardToasts.makeStandardToast(StandardToasts.SUCCESS_UPDATE)
|
||||||
}).catch((err) => {
|
}).catch((err) => {
|
||||||
console.log(err)
|
console.log(err)
|
||||||
StandardToasts.makeStandardToast(StandardToasts.FAIL_UPDATE)
|
StandardToasts.makeStandardToast(StandardToasts.FAIL_UPDATE)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
this.this_item = {...this.blank_item}
|
|
||||||
},
|
},
|
||||||
moveFood: function (source_id, target_id) {
|
moveThis: function (source_id, target_id) {
|
||||||
|
if (source_id === target_id) {
|
||||||
|
this.makeToast(this.$t('Error'), this.$t('Cannot move item to itself'), 'danger')
|
||||||
|
this.clearState()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (!source_id || !target_id) {
|
||||||
|
this.makeToast(this.$t('Warning'), this.$t('Nothing to do'), 'warning')
|
||||||
|
this.clearState()
|
||||||
|
return
|
||||||
|
}
|
||||||
genericAPI(this.this_model, Actions.MOVE, {'source': source_id, 'target': target_id}).then((result) => {
|
genericAPI(this.this_model, Actions.MOVE, {'source': source_id, 'target': target_id}).then((result) => {
|
||||||
if (target_id === 0) {
|
if (target_id === 0) {
|
||||||
let food = this.findCard(source_id, this.foods) || this.findCard(source_id, this.foods2)
|
let item = this.findCard(source_id, this.items_left) || this.findCard(source_id, this.items_right)
|
||||||
this.foods = [food].concat(this.destroyCard(source_id, this.foods)) // order matters, destroy old card before adding it back in at root
|
this.items_left = [item].concat(this.destroyCard(source_id, this.items_left)) // order matters, destroy old card before adding it back in at root
|
||||||
this.foods2 = [...[food]].concat(this.destroyCard(source_id, this.foods2)) // order matters, destroy old card before adding it back in at root
|
this.items_right = [...[item]].concat(this.destroyCard(source_id, this.items_right)) // order matters, destroy old card before adding it back in at root
|
||||||
food.parent = null
|
item.parent = null
|
||||||
} else {
|
} else {
|
||||||
this.foods = this.destroyCard(source_id, this.foods)
|
this.items_left = this.destroyCard(source_id, this.items_left)
|
||||||
this.foods2 = this.destroyCard(source_id, this.foods2)
|
this.items_right = this.destroyCard(source_id, this.items_right)
|
||||||
this.refreshObject(target_id)
|
this.refreshThis(target_id)
|
||||||
}
|
}
|
||||||
// TODO make standard toast
|
// TODO make standard toast
|
||||||
this.makeToast(this.$t('Success'), 'Succesfully moved food', 'success')
|
this.makeToast(this.$t('Success'), 'Succesfully moved resource', 'success')
|
||||||
}).catch((err) => {
|
}).catch((err) => {
|
||||||
// TODO none of the error checking works because the openapi generated functions don't throw an error?
|
// TODO none of the error checking works because the openapi generated functions don't throw an error?
|
||||||
// or i'm capturing it incorrectly
|
// or i'm capturing it incorrectly
|
||||||
@ -326,26 +257,38 @@ export default {
|
|||||||
this.makeToast(this.$t('Error'), err.bodyText, 'danger')
|
this.makeToast(this.$t('Error'), err.bodyText, 'danger')
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
mergeFood: function (source_id, target_id) {
|
mergeThis: function (source_id, target_id) {
|
||||||
|
if (source_id === target_id) {
|
||||||
|
this.makeToast(this.$t('Error'), this.$t('Cannot merge item with itself'), 'danger')
|
||||||
|
this.clearState()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (!source_id || !target_id) {
|
||||||
|
this.makeToast(this.$t('Warning'), this.$t('Nothing to do'), 'warning')
|
||||||
|
this.clearState()
|
||||||
|
return
|
||||||
|
}
|
||||||
genericAPI(this.this_model, Actions.MERGE, {'source': source_id, 'target': target_id}).then((result) => {
|
genericAPI(this.this_model, Actions.MERGE, {'source': source_id, 'target': target_id}).then((result) => {
|
||||||
this.foods = this.destroyCard(source_id, this.foods)
|
this.items_left = this.destroyCard(source_id, this.items_left)
|
||||||
this.foods2 = this.destroyCard(source_id, this.foods2)
|
this.items_right = this.destroyCard(source_id, this.items_right)
|
||||||
this.refreshObject(target_id)
|
this.refreshThis(target_id)
|
||||||
|
// TODO make standard toast
|
||||||
|
this.makeToast(this.$t('Success'), 'Succesfully merged resource', 'success')
|
||||||
}).catch((err) => {
|
}).catch((err) => {
|
||||||
|
//TODO error checking not working with OpenAPI methods
|
||||||
console.log('Error', err)
|
console.log('Error', err)
|
||||||
this.makeToast(this.$t('Error'), err.bodyText, 'danger')
|
this.makeToast(this.$t('Error'), err.bodyText, 'danger')
|
||||||
})
|
})
|
||||||
// TODO make standard toast
|
|
||||||
this.makeToast(this.$t('Success'), 'Succesfully merged food', 'success')
|
|
||||||
},
|
},
|
||||||
getChildren: function(col, food){
|
getChildren: function(col, item){
|
||||||
let parent = {}
|
let parent = {}
|
||||||
let options = {
|
let options = {
|
||||||
'root': food.id,
|
'root': item.id,
|
||||||
'pageSize': 200
|
'pageSize': 200
|
||||||
}
|
}
|
||||||
genericAPI(this.this_model, Actions.LIST, options).then((result) => {
|
genericAPI(this.this_model, Actions.LIST, options).then((result) => {
|
||||||
parent = this.findCard(food.id, col === 'left' ? this.foods : this.foods2)
|
parent = this.findCard(item.id, col === 'left' ? this.items_left : this.items_right)
|
||||||
if (parent) {
|
if (parent) {
|
||||||
Vue.set(parent, 'children', result.data.results)
|
Vue.set(parent, 'children', result.data.results)
|
||||||
Vue.set(parent, 'show_children', true)
|
Vue.set(parent, 'show_children', true)
|
||||||
@ -358,13 +301,13 @@ export default {
|
|||||||
},
|
},
|
||||||
getRecipes: function(col, food){
|
getRecipes: function(col, food){
|
||||||
let parent = {}
|
let parent = {}
|
||||||
|
// TODO: make this generic
|
||||||
let options = {
|
let options = {
|
||||||
'foods': food.id,
|
'foods': food.id,
|
||||||
'pageSize': 200
|
'pageSize': 200
|
||||||
}
|
}
|
||||||
|
|
||||||
genericAPI(Models.RECIPE, Actions.LIST, options).then((result) => {
|
genericAPI(Models.RECIPE, Actions.LIST, options).then((result) => {
|
||||||
parent = this.findCard(food.id, col === 'left' ? this.foods : this.foods2)
|
parent = this.findCard(food.id, col === 'left' ? this.items_left : this.items_right)
|
||||||
if (parent) {
|
if (parent) {
|
||||||
Vue.set(parent, 'recipes', result.data.results)
|
Vue.set(parent, 'recipes', result.data.results)
|
||||||
Vue.set(parent, 'show_recipes', true)
|
Vue.set(parent, 'show_recipes', true)
|
||||||
@ -376,32 +319,28 @@ export default {
|
|||||||
this.makeToast(this.$t('Error'), err.bodyText, 'danger')
|
this.makeToast(this.$t('Error'), err.bodyText, 'danger')
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
refreshObject: function(id){
|
refreshThis: function(id){
|
||||||
this.getThis(id).then(result => {
|
this.getThis(id).then(result => {
|
||||||
this.refreshCard(result.data, this.foods)
|
this.refreshCard(result.data, this.items_left)
|
||||||
this.refreshCard({...result.data}, this.foods2)
|
this.refreshCard({...result.data}, this.items_right)
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
// this would move with modals with mixin?
|
deleteThis: function(id) {
|
||||||
prepareEmoji: function() {
|
|
||||||
this.$refs._edit.addText(this.this_item.icon || '');
|
|
||||||
this.$refs._edit.blur()
|
|
||||||
document.getElementById('btn-emoji-default').disabled = true;
|
|
||||||
},
|
|
||||||
// this would move with modals with mixin?
|
|
||||||
setIcon: function(icon) {
|
|
||||||
this.this_item.icon = icon
|
|
||||||
},
|
|
||||||
deleteThis: function(id, model) {
|
|
||||||
genericAPI(this.this_model, Actions.DELETE, {'id': id}).then((result) => {
|
genericAPI(this.this_model, Actions.DELETE, {'id': id}).then((result) => {
|
||||||
this.foods = this.destroyCard(id, this.foods)
|
this.items_left = this.destroyCard(id, this.items_left)
|
||||||
this.foods2 = this.destroyCard(id, this.foods2)
|
this.items_right = this.destroyCard(id, this.items_right)
|
||||||
StandardToasts.makeStandardToast(StandardToasts.SUCCESS_DELETE)
|
StandardToasts.makeStandardToast(StandardToasts.SUCCESS_DELETE)
|
||||||
}).catch((err) => {
|
}).catch((err) => {
|
||||||
console.log(err)
|
console.log(err)
|
||||||
StandardToasts.makeStandardToast(StandardToasts.FAIL_DELETE)
|
StandardToasts.makeStandardToast(StandardToasts.FAIL_DELETE)
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
clearState: function() {
|
||||||
|
this.show_modal = false
|
||||||
|
this.this_action = undefined
|
||||||
|
this.this_item = undefined
|
||||||
|
this.this_target = undefined
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11,22 +11,22 @@
|
|||||||
@drop="handleDragDrop($event)">
|
@drop="handleDragDrop($event)">
|
||||||
<b-row no-gutters style="height:inherit;">
|
<b-row no-gutters style="height:inherit;">
|
||||||
<b-col no-gutters md="3" style="height:inherit;">
|
<b-col no-gutters md="3" style="height:inherit;">
|
||||||
<b-card-img-lazy style="object-fit: cover; height: 10vh;" :src="model_image" v-bind:alt="$t('Recipe_Image')"></b-card-img-lazy>
|
<b-card-img-lazy style="object-fit: cover; height: 10vh;" :src="item_image" v-bind:alt="$t('Recipe_Image')"></b-card-img-lazy>
|
||||||
</b-col>
|
</b-col>
|
||||||
<b-col no-gutters md="9" style="height:inherit;">
|
<b-col no-gutters md="9" style="height:inherit;">
|
||||||
<b-card-body class="m-0 py-0" style="height:inherit;">
|
<b-card-body class="m-0 py-0" style="height:inherit;">
|
||||||
<b-card-text class=" h-100 my-0 d-flex flex-column" style="text-overflow: ellipsis">
|
<b-card-text class=" h-100 my-0 d-flex flex-column" style="text-overflow: ellipsis">
|
||||||
<h5 class="m-0 mt-1 text-truncate">{{ model[title] }}</h5>
|
<h5 class="m-0 mt-1 text-truncate">{{ item[title] }}</h5>
|
||||||
<div class= "m-0 text-truncate">{{ model[subtitle] }}</div>
|
<div class= "m-0 text-truncate">{{ item[subtitle] }}</div>
|
||||||
<div class="mt-auto mb-1 d-flex flex-row justify-content-end">
|
<div class="mt-auto mb-1 d-flex flex-row justify-content-end">
|
||||||
<div v-if="model[child_count] !=0" class="mx-2 btn btn-link btn-sm"
|
<div v-if="item[child_count] !=0" class="mx-2 btn btn-link btn-sm"
|
||||||
style="z-index: 800;" v-on:click="$emit('item-action',{'action':'get-children','source':model})">
|
style="z-index: 800;" v-on:click="$emit('item-action',{'action':'get-children','source':item})">
|
||||||
<div v-if="!model.show_children">{{ model[child_count] }} {{ model_name }}</div>
|
<div v-if="!item.show_children">{{ item[child_count] }} {{ item_type }}</div>
|
||||||
<div v-else>{{ text.hide_children }}</div>
|
<div v-else>{{ text.hide_children }}</div>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="model[recipe_count]" class="mx-2 btn btn-link btn-sm" style="z-index: 800;"
|
<div v-if="item[recipe_count]" class="mx-2 btn btn-link btn-sm" style="z-index: 800;"
|
||||||
v-on:click="$emit('item-action',{'action':'get-recipes','source':model})">
|
v-on:click="$emit('item-action',{'action':'get-recipes','source':item})">
|
||||||
<div v-if="!model.show_recipes">{{ model[recipe_count] }} {{$t('Recipes')}}</div>
|
<div v-if="!item.show_recipes">{{ item[recipe_count] }} {{$t('Recipes')}}</div>
|
||||||
<div v-else>{{$t('Hide_Recipes')}}</div>
|
<div v-else>{{$t('Hide_Recipes')}}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -38,18 +38,18 @@
|
|||||||
<generic-context-menu class="p-0"
|
<generic-context-menu class="p-0"
|
||||||
:show_merge="merge"
|
:show_merge="merge"
|
||||||
:show_move="move"
|
:show_move="move"
|
||||||
@item-action="$emit('item-action', {'action': $event, 'source': model})">
|
@item-action="$emit('item-action', {'action': $event, 'source': item})">
|
||||||
</generic-context-menu>
|
</generic-context-menu>
|
||||||
</div>
|
</div>
|
||||||
</b-row>
|
</b-row>
|
||||||
</b-card>
|
</b-card>
|
||||||
<!-- recursively add child cards -->
|
<!-- recursively add child cards -->
|
||||||
<div class="row" v-if="model.show_children">
|
<div class="row" v-if="item.show_children">
|
||||||
<div class="col-md-11 offset-md-1">
|
<div class="col-md-11 offset-md-1">
|
||||||
<generic-horizontal-card v-for="child in model[children]" v-bind:key="child.id"
|
<generic-horizontal-card v-for="child in item[children]" v-bind:key="child.id"
|
||||||
:draggable="draggable"
|
:draggable="draggable"
|
||||||
:model="child"
|
:item="child"
|
||||||
:model_name="model_name"
|
:item_type="item_type"
|
||||||
:title="title"
|
:title="title"
|
||||||
:subtitle="subtitle"
|
:subtitle="subtitle"
|
||||||
:child_count="child_count"
|
:child_count="child_count"
|
||||||
@ -63,10 +63,10 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- conditionally view recipes -->
|
<!-- conditionally view recipes -->
|
||||||
<div class="row" v-if="model.show_recipes">
|
<div class="row" v-if="item.show_recipes">
|
||||||
<div class="col-md-11 offset-md-1">
|
<div class="col-md-11 offset-md-1">
|
||||||
<div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));grid-gap: 1rem;">
|
<div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));grid-gap: 1rem;">
|
||||||
<recipe-card v-for="r in model[recipes]"
|
<recipe-card v-for="r in item[recipes]"
|
||||||
v-bind:key="r.id"
|
v-bind:key="r.id"
|
||||||
:recipe="r">
|
:recipe="r">
|
||||||
</recipe-card>
|
</recipe-card>
|
||||||
@ -75,11 +75,11 @@
|
|||||||
</div>
|
</div>
|
||||||
<!-- this should be made a generic component, would also require mixin for functions that generate the popup and put in parent container-->
|
<!-- this should be made a generic component, would also require mixin for functions that generate the popup and put in parent container-->
|
||||||
<b-list-group ref="tooltip" variant="light" v-show="show_menu" v-on-clickaway="closeMenu" style="z-index:9999; cursor:pointer">
|
<b-list-group ref="tooltip" variant="light" v-show="show_menu" v-on-clickaway="closeMenu" style="z-index:9999; cursor:pointer">
|
||||||
<b-list-group-item v-if="move" action v-on:click="$emit('item-action',{'action': 'move', 'target': model, 'source': source}); closeMenu()">
|
<b-list-group-item v-if="move" action v-on:click="$emit('item-action',{'action': 'move', 'target': item, 'source': source}); closeMenu()">
|
||||||
{{$t('Move')}}: {{$t('move_confirmation', {'child': source.name,'parent':model.name})}}
|
<i class="fas fa-expand-arrows-alt fa-fw"></i> {{$t('Move')}}: {{$t('move_confirmation', {'child': source.name,'parent':item.name})}}
|
||||||
</b-list-group-item>
|
</b-list-group-item>
|
||||||
<b-list-group-item v-if="merge" action v-on:click="$emit('item-action',{'action': 'merge', 'target': model, 'source': source}); closeMenu()">
|
<b-list-group-item v-if="merge" action v-on:click="$emit('item-action',{'action': 'merge', 'target': item, 'source': source}); closeMenu()">
|
||||||
{{$t('Merge')}}: {{ $t('merge_confirmation', {'source': source.name,'target':model.name}) }}
|
<i class="fas fa-compress-arrows-alt fa-fw"></i> {{$t('Merge')}}: {{ $t('merge_confirmation', {'source': source.name,'target':item.name}) }}
|
||||||
</b-list-group-item>
|
</b-list-group-item>
|
||||||
<b-list-group-item action v-on:click="closeMenu()">
|
<b-list-group-item action v-on:click="closeMenu()">
|
||||||
{{$t('Cancel')}}
|
{{$t('Cancel')}}
|
||||||
@ -101,8 +101,8 @@ export default {
|
|||||||
components: { GenericContextMenu, RecipeCard },
|
components: { GenericContextMenu, RecipeCard },
|
||||||
mixins: [clickaway],
|
mixins: [clickaway],
|
||||||
props: {
|
props: {
|
||||||
model: Object,
|
item: Object,
|
||||||
model_name: {type: String, default: 'Blank Model'}, // TODO update translations to handle plural translations
|
item_type: {type: String, default: 'Blank Item Type'}, // TODO update translations to handle plural translations
|
||||||
draggable: {type: Boolean, default: false},
|
draggable: {type: Boolean, default: false},
|
||||||
title: {type: String, default: 'name'},
|
title: {type: String, default: 'name'},
|
||||||
subtitle: {type: String, default: 'description'},
|
subtitle: {type: String, default: 'description'},
|
||||||
@ -115,7 +115,7 @@ export default {
|
|||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
model_image: '',
|
item_image: '',
|
||||||
over: false,
|
over: false,
|
||||||
show_menu: false,
|
show_menu: false,
|
||||||
dragMenu: undefined,
|
dragMenu: undefined,
|
||||||
@ -128,14 +128,14 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
this.model_image = this.model?.image ?? window.IMAGE_PLACEHOLDER
|
this.item_image = this.item?.image ?? window.IMAGE_PLACEHOLDER
|
||||||
this.dragMenu = this.$refs.tooltip
|
this.dragMenu = this.$refs.tooltip
|
||||||
this.text.hide_children = this.$t('Hide_' + this.model_name)
|
this.text.hide_children = this.$t('Hide_' + this.item_type)
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
handleDragStart: function(e) {
|
handleDragStart: function(e) {
|
||||||
this.isError = false
|
this.isError = false
|
||||||
e.dataTransfer.setData('source', JSON.stringify(this.model))
|
e.dataTransfer.setData('source', JSON.stringify(this.item))
|
||||||
},
|
},
|
||||||
handleDragEnter: function(e) {
|
handleDragEnter: function(e) {
|
||||||
if (!e.currentTarget.contains(e.relatedTarget) && e.relatedTarget != null) {
|
if (!e.currentTarget.contains(e.relatedTarget) && e.relatedTarget != null) {
|
||||||
@ -149,7 +149,7 @@ export default {
|
|||||||
},
|
},
|
||||||
handleDragDrop: function(e) {
|
handleDragDrop: function(e) {
|
||||||
let source = JSON.parse(e.dataTransfer.getData('source'))
|
let source = JSON.parse(e.dataTransfer.getData('source'))
|
||||||
if (source.id != this.model.id){
|
if (source.id != this.item.id){
|
||||||
this.source = source
|
this.source = source
|
||||||
let menuLocation = {getBoundingClientRect: this.generateLocation(e.clientX, e.clientY),}
|
let menuLocation = {getBoundingClientRect: this.generateLocation(e.clientX, e.clientY),}
|
||||||
this.show_menu = true
|
this.show_menu = true
|
||||||
@ -176,7 +176,7 @@ export default {
|
|||||||
})
|
})
|
||||||
popper.update()
|
popper.update()
|
||||||
this.over = false
|
this.over = false
|
||||||
this.$emit({'action': 'drop', 'target': this.model, 'source': this.source})
|
this.$emit({'action': 'drop', 'target': this.item, 'source': this.source})
|
||||||
} else {
|
} else {
|
||||||
this.isError = true
|
this.isError = true
|
||||||
}
|
}
|
||||||
|
@ -76,7 +76,7 @@
|
|||||||
<template v-slot:no-more><span/></template>
|
<template v-slot:no-more><span/></template>
|
||||||
</infinite-loading>
|
</infinite-loading>
|
||||||
</div>
|
</div>
|
||||||
<!-- right side food cards -->
|
<!-- right side cards -->
|
||||||
<div class="col col-md mh-100 overflow-auto" v-if="show_split">
|
<div class="col col-md mh-100 overflow-auto" v-if="show_split">
|
||||||
<slot name="cards-right"></slot>
|
<slot name="cards-right"></slot>
|
||||||
<infinite-loading
|
<infinite-loading
|
||||||
@ -119,8 +119,6 @@ export default {
|
|||||||
left_page: 0,
|
left_page: 0,
|
||||||
right: +new Date(),
|
right: +new Date(),
|
||||||
left: +new Date(),
|
left: +new Date(),
|
||||||
isDirtyright: false,
|
|
||||||
isDirtyleft: false,
|
|
||||||
text: {
|
text: {
|
||||||
'new': '',
|
'new': '',
|
||||||
'name': '',
|
'name': '',
|
||||||
@ -133,7 +131,6 @@ export default {
|
|||||||
mounted() {
|
mounted() {
|
||||||
this.dragMenu = this.$refs.tooltip
|
this.dragMenu = this.$refs.tooltip
|
||||||
this.text.new = this.$t('New_' + this.list_name)
|
this.text.new = this.$t('New_' + this.list_name)
|
||||||
this.text.name = this.$t(this.list_name)
|
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
search_right: _debounce(function() {
|
search_right: _debounce(function() {
|
||||||
@ -170,6 +167,7 @@ export default {
|
|||||||
'page': (col==='left') ? this.left_page + 1 : this.right_page + 1,
|
'page': (col==='left') ? this.left_page + 1 : this.right_page + 1,
|
||||||
'column': col
|
'column': col
|
||||||
}
|
}
|
||||||
|
// TODO: change this to be an emit and watch a prop to determine if loaded or complete
|
||||||
new Promise((callback) => this.$emit('get-list', params, callback)).then((result) => {
|
new Promise((callback) => this.$emit('get-list', params, callback)).then((result) => {
|
||||||
this[col+'_page']+=1
|
this[col+'_page']+=1
|
||||||
$state.loaded();
|
$state.loaded();
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<b-modal class="modal" id="modal" >
|
<b-modal class="modal" id="modal" @hidden="cancelAction">
|
||||||
<template v-slot:modal-title><h4>{{form.title}}</h4></template>
|
<template v-slot:modal-title><h4>{{form.title}}</h4></template>
|
||||||
<div v-for="(f, i) in form.fields" v-bind:key=i>
|
<div v-for="(f, i) in form.fields" v-bind:key=i>
|
||||||
<p v-if="f.type=='instruction'">{{f.label}}</p>
|
<p v-if="f.type=='instruction'">{{f.label}}</p>
|
||||||
@ -10,7 +10,8 @@
|
|||||||
:field="f.field"
|
:field="f.field"
|
||||||
:model="listModel(f.list)"
|
:model="listModel(f.list)"
|
||||||
:sticky_options="f.sticky_options || undefined"
|
:sticky_options="f.sticky_options || undefined"
|
||||||
@change="changeValue"/> <!-- TODO add ability to create new items associated with lookup -->
|
@change="storeValue"/> <!-- TODO add ability to create new items associated with lookup -->
|
||||||
|
<!-- TODO: add emoji field -->
|
||||||
<checkbox-input v-if="f.type=='checkbox'"
|
<checkbox-input v-if="f.type=='checkbox'"
|
||||||
:label="f.label"
|
:label="f.label"
|
||||||
:value="f.value"
|
:value="f.value"
|
||||||
@ -23,11 +24,10 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<template v-slot:modal-footer>
|
<template v-slot:modal-footer>
|
||||||
<b-button class="float-right mx-1" variant="secondary" v-on:click="$bvModal.hide('modal')">{{$t('Cancel')}}</b-button>
|
<b-button class="float-right mx-1" variant="secondary" v-on:click="cancelAction">{{$t('Cancel')}}</b-button>
|
||||||
<b-button class="float-right mx-1" variant="primary" v-on:click="doAction">{{form.ok_label}}</b-button>
|
<b-button class="float-right mx-1" variant="primary" v-on:click="doAction">{{form.ok_label}}</b-button>
|
||||||
</template>
|
</template>
|
||||||
</b-modal>
|
</b-modal>
|
||||||
<b-button v-on:click="Button">ok</b-button>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@ -55,19 +55,13 @@ export default {
|
|||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
new_item: {},
|
form_data: {},
|
||||||
form: {},
|
form: {},
|
||||||
buttons: {
|
dirty: false
|
||||||
'new':{'label': this.$t('Save')},
|
|
||||||
'delete':{'label': this.$t('Delete')},
|
|
||||||
'edit':{'label': this.$t('Save')},
|
|
||||||
'move':{'label': this.$t('Move')},
|
|
||||||
'merge':{'label': this.$t('Merge')}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
this.$root.$on('change', this.changeValue); // modal is outside Vue instance(?) so have to listen at root of component
|
this.$root.$on('change', this.storeValue); // modal is outside Vue instance(?) so have to listen at root of component
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
buttonLabel() {
|
buttonLabel() {
|
||||||
@ -78,30 +72,27 @@ export default {
|
|||||||
'show': function () {
|
'show': function () {
|
||||||
if (this.show) {
|
if (this.show) {
|
||||||
this.form = getForm(this.model, this.action, this.item1, this.item2)
|
this.form = getForm(this.model, this.action, this.item1, this.item2)
|
||||||
|
this.dirty = true
|
||||||
this.$bvModal.show('modal')
|
this.$bvModal.show('modal')
|
||||||
|
} else {
|
||||||
|
this.$bvModal.hide('modal')
|
||||||
|
this.form_data = {}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
Button: function(e) {
|
|
||||||
this.form = getForm(this.model, this.action, this.item1, this.item2)
|
|
||||||
console.log(this.form)
|
|
||||||
this.$bvModal.show('modal')
|
|
||||||
},
|
|
||||||
doAction: function(){
|
doAction: function(){
|
||||||
let alert_text = ''
|
this.dirty = false
|
||||||
for (const [k, v] of Object.entries(this.form.fields)) {
|
this.$emit('finish-action', {'form_data': this.form_data })
|
||||||
if (v.type !== 'instruction'){
|
|
||||||
alert_text = alert_text + v.field + ": " + this.new_item[v.field] + "\n"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this.$nextTick(function() {this.$bvModal.hide('modal')})
|
|
||||||
setTimeout(() => {}, 0) // confirm that the
|
|
||||||
alert(alert_text)
|
|
||||||
},
|
},
|
||||||
changeValue: function(field, value) {
|
cancelAction: function() {
|
||||||
// console.log('catch change', field, value)
|
if (this.dirty) {
|
||||||
this.new_item[field] = value
|
this.dirty = false
|
||||||
|
this.$emit('finish-action', 'cancel')
|
||||||
|
}
|
||||||
|
},
|
||||||
|
storeValue: function(field, value) {
|
||||||
|
this.form_data[field] = value
|
||||||
},
|
},
|
||||||
listModel: function(m) {
|
listModel: function(m) {
|
||||||
if (m === 'self') {
|
if (m === 'self') {
|
||||||
|
@ -120,5 +120,6 @@
|
|||||||
"edit_title": "Edit {type}",
|
"edit_title": "Edit {type}",
|
||||||
"Name": "Name",
|
"Name": "Name",
|
||||||
"Description": "Description",
|
"Description": "Description",
|
||||||
"Recipe": "Recipe"
|
"Recipe": "Recipe",
|
||||||
|
"tree_root": "Root of Tree"
|
||||||
}
|
}
|
||||||
|
@ -43,6 +43,17 @@ export class Models {
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
'move': {
|
||||||
|
'form': {
|
||||||
|
'target': {
|
||||||
|
'form_field': true,
|
||||||
|
'type': 'lookup',
|
||||||
|
'field': 'target',
|
||||||
|
'list': 'self',
|
||||||
|
'sticky_options': [{'id': 0,'name': i18n.t('tree_root')}]
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -48,7 +48,7 @@ export class StandardToasts {
|
|||||||
makeToast(i18n.tc('Success'), i18n.tc('success_deleting_resource'), 'success')
|
makeToast(i18n.tc('Success'), i18n.tc('success_deleting_resource'), 'success')
|
||||||
break;
|
break;
|
||||||
case StandardToasts.FAIL_CREATE:
|
case StandardToasts.FAIL_CREATE:
|
||||||
makeToast(i18n.tc('Failure'), i18n.tc('success_creating_resource'), 'danger')
|
makeToast(i18n.tc('Failure'), i18n.tc('err_creating_resource'), 'danger')
|
||||||
break;
|
break;
|
||||||
case StandardToasts.FAIL_FETCH:
|
case StandardToasts.FAIL_FETCH:
|
||||||
makeToast(i18n.tc('Failure'), i18n.tc('err_fetching_resource'), 'danger')
|
makeToast(i18n.tc('Failure'), i18n.tc('err_fetching_resource'), 'danger')
|
||||||
@ -167,7 +167,6 @@ export function genericAPI(model, action, options) {
|
|||||||
let config = setup?.config ?? {}
|
let config = setup?.config ?? {}
|
||||||
let params = setup?.params ?? []
|
let params = setup?.params ?? []
|
||||||
let parameters = []
|
let parameters = []
|
||||||
|
|
||||||
let this_value = undefined
|
let this_value = undefined
|
||||||
params.forEach(function (item, index) {
|
params.forEach(function (item, index) {
|
||||||
if (Array.isArray(item)) {
|
if (Array.isArray(item)) {
|
||||||
@ -181,8 +180,7 @@ export function genericAPI(model, action, options) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
this_value = options?.[item] ?? undefined
|
this_value = formatParam(config?.[item], options?.[item] ?? undefined)
|
||||||
if (this_value) {this_value = formatParam(config?.[item], this_value)}
|
|
||||||
}
|
}
|
||||||
// if no value is found so far, get the default if it exists
|
// if no value is found so far, get the default if it exists
|
||||||
if (!this_value) {
|
if (!this_value) {
|
||||||
@ -272,7 +270,6 @@ export function getForm(model, action, item1, item2) {
|
|||||||
let config = {...action?.form, ...model.model_type?.[f]?.form, ...model?.[f]?.form}
|
let config = {...action?.form, ...model.model_type?.[f]?.form, ...model?.[f]?.form}
|
||||||
// if not defined partialUpdate will use form from create
|
// if not defined partialUpdate will use form from create
|
||||||
if (f === 'partialUpdate' && Object.keys(config).length == 0) {
|
if (f === 'partialUpdate' && Object.keys(config).length == 0) {
|
||||||
console.log('create form',Actions.CREATE?.form)
|
|
||||||
config = {...Actions.CREATE?.form, ...model.model_type?.['create']?.form, ...model?.['create']?.form}
|
config = {...Actions.CREATE?.form, ...model.model_type?.['create']?.form, ...model?.['create']?.form}
|
||||||
config['title'] = {...action?.form_title, ...model.model_type?.[f]?.form_title, ...model?.[f]?.form_title}
|
config['title'] = {...action?.form_title, ...model.model_type?.[f]?.form_title, ...model?.[f]?.form_title}
|
||||||
}
|
}
|
||||||
@ -288,6 +285,7 @@ export function getForm(model, action, item1, item2) {
|
|||||||
value = v
|
value = v
|
||||||
}
|
}
|
||||||
if (value?.form_field) {
|
if (value?.form_field) {
|
||||||
|
value['value'] = item1?.[value?.field] ?? undefined
|
||||||
form.fields.push(
|
form.fields.push(
|
||||||
{
|
{
|
||||||
...value,
|
...value,
|
||||||
@ -301,7 +299,6 @@ export function getForm(model, action, item1, item2) {
|
|||||||
form[k] = value
|
form[k] = value
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
console.log('utils form', form)
|
|
||||||
return form
|
return form
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -374,7 +371,7 @@ export const CardMixin = {
|
|||||||
let idx = undefined
|
let idx = undefined
|
||||||
target = this.findCard(obj.id, card_list)
|
target = this.findCard(obj.id, card_list)
|
||||||
|
|
||||||
if (target.parent) {
|
if (target?.parent) {
|
||||||
let parent = this.findCard(target.parent, card_list)
|
let parent = this.findCard(target.parent, card_list)
|
||||||
if (parent) {
|
if (parent) {
|
||||||
if (parent.show_children){
|
if (parent.show_children){
|
||||||
@ -382,7 +379,7 @@ export const CardMixin = {
|
|||||||
Vue.set(parent.children, idx, obj)
|
Vue.set(parent.children, idx, obj)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else if (target) {
|
||||||
idx = card_list.indexOf(card_list.find(x => x.id === target.id))
|
idx = card_list.indexOf(card_list.find(x => x.id === target.id))
|
||||||
Vue.set(card_list, idx, obj)
|
Vue.set(card_list, idx, obj)
|
||||||
}
|
}
|
||||||
|
@ -85,7 +85,7 @@ module.exports = {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
// TODO make this conditional on .env DEBUG = FALSE
|
// TODO make this conditional on .env DEBUG = FALSE
|
||||||
config.optimization.minimize(false)
|
config.optimization.minimize(true)
|
||||||
);
|
);
|
||||||
|
|
||||||
//TODO somehow remov them as they are also added to the manifest config of the service worker
|
//TODO somehow remov them as they are also added to the manifest config of the service worker
|
||||||
|
Loading…
Reference in New Issue
Block a user