food batch update dialog and first api functions

This commit is contained in:
vabene1111
2025-09-10 07:54:42 +02:00
parent fc4b017d30
commit 1188624376
9 changed files with 516 additions and 12 deletions

View File

@@ -1198,6 +1198,26 @@ class FoodBatchUpdateSerializer(serializers.Serializer):
category = serializers.IntegerField(required=False, allow_null=True)
substitute_add = serializers.ListField(child=serializers.IntegerField())
substitute_remove = serializers.ListField(child=serializers.IntegerField())
substitute_set = serializers.ListField(child=serializers.IntegerField())
substitute_remove_all = serializers.BooleanField(default=False)
inherit_fields_add = serializers.ListField(child=serializers.IntegerField())
inherit_fields_remove = serializers.ListField(child=serializers.IntegerField())
inherit_fields_set = serializers.ListField(child=serializers.IntegerField())
inherit_fields_remove_all = serializers.BooleanField(default=False)
child_inherit_fields_add = serializers.ListField(child=serializers.IntegerField())
child_inherit_fields_remove = serializers.ListField(child=serializers.IntegerField())
child_inherit_fields_set = serializers.ListField(child=serializers.IntegerField())
child_inherit_fields_remove_all = serializers.BooleanField(default=False)
substitute_children = serializers.BooleanField(required=False, allow_null=True)
substitute_siblings = serializers.BooleanField(required=False, allow_null=True)
ignore_shopping = serializers.BooleanField(required=False, allow_null=True)
on_hand = serializers.BooleanField(required=False, allow_null=True)
class CustomFilterSerializer(SpacedModelSerializer, WritableNestedModelSerializer):
shared = UserSerializer(many=True, required=False)

View File

@@ -946,10 +946,50 @@ class FoodViewSet(LoggingMixin, TreeMixin):
if serializer.is_valid():
foods = Food.objects.filter(id__in=serializer.validated_data['foods'], space=self.request.space)
# safe_food_ids = Food.objects.filter(id__in=serializer.validated_data['foods'], space=self.request.space).values_list('id', flat=True)
safe_food_ids = Food.objects.filter(id__in=serializer.validated_data['foods'], space=self.request.space).values_list('id', flat=True)
if 'category' in serializer.validated_data:
foods.update(category_id=serializer.validated_data['category'])
foods.update(supermarket_category_id=serializer.validated_data['category'])
if 'ignore_shopping' in serializer.validated_data and serializer.validated_data['ignore_shopping'] is not None:
foods.update(ignore_shopping=serializer.validated_data['ignore_shopping'])
if 'on_hand' in serializer.validated_data and serializer.validated_data['on_hand'] is not None:
if serializer.validated_data['on_hand']:
user_relation = []
for f in safe_food_ids:
user_relation.append(Food.onhand_users.through(food_id=f, user_id=request.user.id))
Food.onhand_users.through.objects.bulk_create(user_relation, ignore_conflicts=True, unique_fields=('food_id', 'user_id',))
else:
Food.onhand_users.through.objects.filter(food_id__in=safe_food_ids, user_id=request.user.id).delete()
if 'substitutes_add' in serializer.validated_data:
substitute_relation = []
for f in safe_food_ids:
for s in serializer.validated_data['substitutes_add']:
substitute_relation.append(Food.substitute.through(from_food_id=f, to_food_id=s))
Food.substitute.through.objects.bulk_create(substitute_relation, ignore_conflicts=True, unique_fields=('from_food_id', 'to_food_id',))
if 'substitute_remove' in serializer.validated_data:
for s in serializer.validated_data['substitute_remove']:
Food.substitute.through.objects.filter(from_food_id=safe_food_ids, to_food_id=s).delete()
if 'substitute_set' in serializer.validated_data and len(serializer.validated_data['substitute_set']) > 0:
substitute_relation = []
Food.substitute.through.objects.filter(from_food_id=safe_food_ids).delete()
for f in safe_food_ids:
for s in serializer.validated_data['substitute_set']:
substitute_relation.append(Food.substitute.through(from_food_id=f, to_food_id=s))
Food.substitute.through.objects.bulk_create(substitute_relation, ignore_conflicts=True, unique_fields=('from_food_id', 'to_food_id',))
if 'substitute_remove_all' in serializer.validated_data and serializer.validated_data['substitute_remove_all']:
Food.substitute.through.objects.filter(from_food_id=safe_food_ids).delete()
def add_substitute(relation_model, base_field, base_ids, related_field_name, related_ids ):
pass
return Response({}, 200)

View File

@@ -0,0 +1,178 @@
<template>
<v-dialog max-width="1200px" :activator="props.activator" v-model="dialog">
<v-card :loading="loading">
<v-closable-card-title
:title="$t('BatchEdit')"
:sub-title="$t('BatchEditUpdatingItemsCount', {type: $t('Foods'), count: updateItems.length})"
:icon="TFood.icon"
v-model="dialog"
></v-closable-card-title>
<v-divider></v-divider>
<v-card-text>
<v-form>
<v-row>
<v-col cols="12" md="6">
<v-card :title="$t('Miscellaneous')" prepend-icon="fa-solid fa-list" variant="flat">
<v-card-text>
<model-select model="SupermarketCategory" v-model="batchUpdateRequest.foodBatchUpdate.category" :object="false" allow-create mode="single">
</model-select>
<v-select :items="boolUpdateOptions" :label="$t('Ignore_Shopping')" clearable v-model="batchUpdateRequest.foodBatchUpdate.ignoreShopping"></v-select>
<v-select :items="boolUpdateOptions" :label="$t('OnHand')" clearable v-model="batchUpdateRequest.foodBatchUpdate.onHand"></v-select>
<v-spacer></v-spacer>
<v-label :text="$t('Substitutes')"></v-label>
<model-select model="Food" v-model="batchUpdateRequest.foodBatchUpdate.substituteAdd" :object="false" allow-create mode="tags">
<template #prepend>
<v-icon icon="fa-solid fa-add"></v-icon>
</template>
</model-select>
<model-select model="Food" v-model="batchUpdateRequest.foodBatchUpdate.substituteRemove" :object="false" allow-create mode="tags">
<template #prepend>
<v-icon icon="fa-solid fa-minus"></v-icon>
</template>
</model-select>
<model-select model="Food" v-model="batchUpdateRequest.foodBatchUpdate.substituteSet" :object="false" allow-create mode="tags">
<template #prepend>
<v-icon icon="fa-solid fa-equals"></v-icon>
</template>
</model-select>
<v-checkbox :label="$t('RemoveAllType', {type: $t('Substitutes')})" hide-details
v-model="batchUpdateRequest.foodBatchUpdate.substituteRemoveAll"></v-checkbox>
</v-card-text>
</v-card>
</v-col>
<v-col cols="12" md="6">
<v-card :title="$t('Hierarchy')" prepend-icon="fa-solid fa-folder-tree" variant="flat">
<v-card-text>
<v-select :items="boolUpdateOptions" :label="$t('substitute_siblings')" clearable v-model="batchUpdateRequest.foodBatchUpdate.substituteChildren"></v-select>
<v-select :items="boolUpdateOptions" :label="$t('substitute_children')" clearable v-model="batchUpdateRequest.foodBatchUpdate.substituteSiblings"></v-select>
<v-spacer></v-spacer>
<v-label :text="$t('InheritFields')"></v-label>
<model-select model="FoodInheritField" v-model="batchUpdateRequest.foodBatchUpdate.inheritFieldsAdd" :object="false" allow-create mode="tags">
<template #prepend>
<v-icon icon="fa-solid fa-add"></v-icon>
</template>
</model-select>
<model-select model="FoodInheritField" v-model="batchUpdateRequest.foodBatchUpdate.inheritFieldsRemove" :object="false" allow-create mode="tags">
<template #prepend>
<v-icon icon="fa-solid fa-minus"></v-icon>
</template>
</model-select>
<model-select model="FoodInheritField" v-model="batchUpdateRequest.foodBatchUpdate.inheritFieldsSet" :object="false" allow-create mode="tags">
<template #prepend>
<v-icon icon="fa-solid fa-equals"></v-icon>
</template>
</model-select>
<v-checkbox :label="$t('RemoveAllType', {type: $t('InheritFields')})" hide-details
v-model="batchUpdateRequest.foodBatchUpdate.inheritFieldsRemoveAll"></v-checkbox>
<v-spacer></v-spacer>
<v-label :text="$t('ChildInheritFields')"></v-label>
<model-select model="FoodInheritField" v-model="batchUpdateRequest.foodBatchUpdate.childInheritFieldsAdd" :object="false" allow-create mode="tags">
<template #prepend>
<v-icon icon="fa-solid fa-add"></v-icon>
</template>
</model-select>
<model-select model="FoodInheritField" v-model="batchUpdateRequest.foodBatchUpdate.childInheritFieldsRemove" :object="false" allow-create mode="tags">
<template #prepend>
<v-icon icon="fa-solid fa-minus"></v-icon>
</template>
</model-select>
<model-select model="FoodInheritField" v-model="batchUpdateRequest.foodBatchUpdate.childInheritFieldsSet" :object="false" allow-create mode="tags">
<template #prepend>
<v-icon icon="fa-solid fa-equals"></v-icon>
</template>
</model-select>
<v-checkbox :label="$t('RemoveAllType', {type: $t('ChildInheritFields')})" hide-details
v-model="batchUpdateRequest.foodBatchUpdate.childInheritFieldsRemoveAll"></v-checkbox>
</v-card-text>
</v-card>
</v-col>
</v-row>
</v-form>
</v-card-text>
<v-card-actions>
<v-btn :disabled="loading" @click="dialog = false">{{ $t('Cancel') }}</v-btn>
<v-btn color="warning" :loading="loading" @click="batchUpdateFoods()" :disabled="updateItems.length < 1">{{ $t('Update') }}</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
</template>
<script setup lang="ts">
import {onMounted, PropType, ref, watch} from "vue";
import {EditorSupportedModels, EditorSupportedTypes, getGenericModelFromString, TFood, TKeyword, TRecipe} from "@/types/Models.ts";
import VClosableCardTitle from "@/components/dialogs/VClosableCardTitle.vue";
import {useI18n} from "vue-i18n";
import {ApiApi, ApiFoodBatchUpdateUpdateRequest, ApiRecipeBatchUpdateUpdateRequest, Food, Recipe, RecipeOverview} from "@/openapi";
import {ErrorMessageType, useMessageStore} from "@/stores/MessageStore.ts";
import ModelSelect from "@/components/inputs/ModelSelect.vue";
const emit = defineEmits(['change'])
const props = defineProps({
items: {type: Array as PropType<Array<Food>>, required: true},
activator: {type: String, default: 'parent'},
})
const {t} = useI18n()
const dialog = defineModel<boolean>({default: false})
const loading = ref(false)
const updateItems = ref([] as Food[])
const batchUpdateRequest = ref({foodBatchUpdate: {}} as ApiFoodBatchUpdateUpdateRequest)
const boolUpdateOptions = ref([
{value: true, title: t('Yes')},
{value: false, title: t('No')},
])
/**
* copy prop when dialog opens so that items remain when parent is updated after change is emitted
*/
watch(dialog, (newValue, oldValue) => {
if (!oldValue && newValue && props.items != undefined) {
batchUpdateRequest.value.foodBatchUpdate.foods = props.items.flatMap(r => r.id!)
updateItems.value = JSON.parse(JSON.stringify(props.items))
}
})
/**
* perform batch request to update recipes
*/
function batchUpdateFoods() {
let api = new ApiApi()
loading.value = true
api.apiFoodBatchUpdateUpdate(batchUpdateRequest.value).then(r => {
}).catch(err => {
useMessageStore().addError(ErrorMessageType.UPDATE_ERROR, err)
}).finally(() => {
emit('change')
loading.value = false
})
}
</script>
<style scoped>
</style>

View File

@@ -54,7 +54,7 @@
<properties-editor v-model="editingObj.properties" :amount-for="propertiesAmountFor"></properties-editor>
<!-- TODO remove once append to body for model select is working properly -->
<v-spacer style="margin-top: 60px;"></v-spacer>
<v-spacer style="margin-top: 80px;"></v-spacer>
</v-form>
</v-tabs-window-item>
@@ -106,7 +106,7 @@
</v-card>
</v-form>
<!-- TODO remove once append to body for model select is working properly -->
<v-spacer style="margin-top: 60px;"></v-spacer>
<v-spacer style="margin-top: 80px;"></v-spacer>
</v-tabs-window-item>
<v-tabs-window-item value="hierarchy">
@@ -119,6 +119,9 @@
mode="tags"></ModelSelect>
<ModelSelect model="FoodInheritField" v-model="editingObj.childInheritFields" :label="$t('ChildInheritFields')" :hint="$t('ChildInheritFields_help')"
mode="tags"></ModelSelect>
<!-- TODO remove once append to body for model select is working properly -->
<v-spacer style="margin-top: 100px;"></v-spacer>
</v-tabs-window-item>
<v-tabs-window-item value="misc">

View File

@@ -29,6 +29,7 @@ models/ExportRequest.ts
models/FdcQuery.ts
models/FdcQueryFoods.ts
models/Food.ts
models/FoodBatchUpdate.ts
models/FoodInheritField.ts
models/FoodShoppingUpdate.ts
models/FoodSimple.ts

View File

@@ -30,6 +30,7 @@ import type {
ExportRequest,
FdcQuery,
Food,
FoodBatchUpdate,
FoodInheritField,
FoodShoppingUpdate,
Group,
@@ -212,6 +213,8 @@ import {
FdcQueryToJSON,
FoodFromJSON,
FoodToJSON,
FoodBatchUpdateFromJSON,
FoodBatchUpdateToJSON,
FoodInheritFieldFromJSON,
FoodInheritFieldToJSON,
FoodShoppingUpdateFromJSON,
@@ -962,6 +965,10 @@ export interface ApiFdcSearchRetrieveRequest {
query?: string;
}
export interface ApiFoodBatchUpdateUpdateRequest {
foodBatchUpdate: FoodBatchUpdate;
}
export interface ApiFoodCreateRequest {
food: Omit<Food, 'shopping'|'parent'|'numchild'|'fullName'|'substituteOnhand'>;
}
@@ -5956,6 +5963,46 @@ export class ApiApi extends runtime.BaseAPI {
return await response.value();
}
/**
* logs request counts to redis cache total/per user/
*/
async apiFoodBatchUpdateUpdateRaw(requestParameters: ApiFoodBatchUpdateUpdateRequest, initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise<runtime.ApiResponse<FoodBatchUpdate>> {
if (requestParameters['foodBatchUpdate'] == null) {
throw new runtime.RequiredError(
'foodBatchUpdate',
'Required parameter "foodBatchUpdate" was null or undefined when calling apiFoodBatchUpdateUpdate().'
);
}
const queryParameters: any = {};
const headerParameters: runtime.HTTPHeaders = {};
headerParameters['Content-Type'] = 'application/json';
if (this.configuration && this.configuration.apiKey) {
headerParameters["Authorization"] = await this.configuration.apiKey("Authorization"); // ApiKeyAuth authentication
}
const response = await this.request({
path: `/api/food/batch_update/`,
method: 'PUT',
headers: headerParameters,
query: queryParameters,
body: FoodBatchUpdateToJSON(requestParameters['foodBatchUpdate']),
}, initOverrides);
return new runtime.JSONApiResponse(response, (jsonValue) => FoodBatchUpdateFromJSON(jsonValue));
}
/**
* logs request counts to redis cache total/per user/
*/
async apiFoodBatchUpdateUpdate(requestParameters: ApiFoodBatchUpdateUpdateRequest, initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise<FoodBatchUpdate> {
const response = await this.apiFoodBatchUpdateUpdateRaw(requestParameters, initOverrides);
return await response.value();
}
/**
* logs request counts to redis cache total/per user/
*/

View File

@@ -0,0 +1,206 @@
/* tslint:disable */
/* eslint-disable */
/**
* Tandoor
* Tandoor API Docs
*
* The version of the OpenAPI document: 0.0.0
*
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
* https://openapi-generator.tech
* Do not edit the class manually.
*/
import { mapValues } from '../runtime';
/**
*
* @export
* @interface FoodBatchUpdate
*/
export interface FoodBatchUpdate {
/**
*
* @type {Array<number>}
* @memberof FoodBatchUpdate
*/
foods: Array<number>;
/**
*
* @type {number}
* @memberof FoodBatchUpdate
*/
category?: number;
/**
*
* @type {Array<number>}
* @memberof FoodBatchUpdate
*/
substituteAdd: Array<number>;
/**
*
* @type {Array<number>}
* @memberof FoodBatchUpdate
*/
substituteRemove: Array<number>;
/**
*
* @type {Array<number>}
* @memberof FoodBatchUpdate
*/
substituteSet: Array<number>;
/**
*
* @type {boolean}
* @memberof FoodBatchUpdate
*/
substituteRemoveAll?: boolean;
/**
*
* @type {Array<number>}
* @memberof FoodBatchUpdate
*/
inheritFieldsAdd: Array<number>;
/**
*
* @type {Array<number>}
* @memberof FoodBatchUpdate
*/
inheritFieldsRemove: Array<number>;
/**
*
* @type {Array<number>}
* @memberof FoodBatchUpdate
*/
inheritFieldsSet: Array<number>;
/**
*
* @type {boolean}
* @memberof FoodBatchUpdate
*/
inheritFieldsRemoveAll?: boolean;
/**
*
* @type {Array<number>}
* @memberof FoodBatchUpdate
*/
childInheritFieldsAdd: Array<number>;
/**
*
* @type {Array<number>}
* @memberof FoodBatchUpdate
*/
childInheritFieldsRemove: Array<number>;
/**
*
* @type {Array<number>}
* @memberof FoodBatchUpdate
*/
childInheritFieldsSet: Array<number>;
/**
*
* @type {boolean}
* @memberof FoodBatchUpdate
*/
childInheritFieldsRemoveAll?: boolean;
/**
*
* @type {boolean}
* @memberof FoodBatchUpdate
*/
substituteChildren?: boolean;
/**
*
* @type {boolean}
* @memberof FoodBatchUpdate
*/
substituteSiblings?: boolean;
/**
*
* @type {boolean}
* @memberof FoodBatchUpdate
*/
ignoreShopping?: boolean;
/**
*
* @type {boolean}
* @memberof FoodBatchUpdate
*/
onHand?: boolean;
}
/**
* Check if a given object implements the FoodBatchUpdate interface.
*/
export function instanceOfFoodBatchUpdate(value: object): value is FoodBatchUpdate {
if (!('foods' in value) || value['foods'] === undefined) return false;
if (!('substituteAdd' in value) || value['substituteAdd'] === undefined) return false;
if (!('substituteRemove' in value) || value['substituteRemove'] === undefined) return false;
if (!('substituteSet' in value) || value['substituteSet'] === undefined) return false;
if (!('inheritFieldsAdd' in value) || value['inheritFieldsAdd'] === undefined) return false;
if (!('inheritFieldsRemove' in value) || value['inheritFieldsRemove'] === undefined) return false;
if (!('inheritFieldsSet' in value) || value['inheritFieldsSet'] === undefined) return false;
if (!('childInheritFieldsAdd' in value) || value['childInheritFieldsAdd'] === undefined) return false;
if (!('childInheritFieldsRemove' in value) || value['childInheritFieldsRemove'] === undefined) return false;
if (!('childInheritFieldsSet' in value) || value['childInheritFieldsSet'] === undefined) return false;
return true;
}
export function FoodBatchUpdateFromJSON(json: any): FoodBatchUpdate {
return FoodBatchUpdateFromJSONTyped(json, false);
}
export function FoodBatchUpdateFromJSONTyped(json: any, ignoreDiscriminator: boolean): FoodBatchUpdate {
if (json == null) {
return json;
}
return {
'foods': json['foods'],
'category': json['category'] == null ? undefined : json['category'],
'substituteAdd': json['substitute_add'],
'substituteRemove': json['substitute_remove'],
'substituteSet': json['substitute_set'],
'substituteRemoveAll': json['substitute_remove_all'] == null ? undefined : json['substitute_remove_all'],
'inheritFieldsAdd': json['inherit_fields_add'],
'inheritFieldsRemove': json['inherit_fields_remove'],
'inheritFieldsSet': json['inherit_fields_set'],
'inheritFieldsRemoveAll': json['inherit_fields_remove_all'] == null ? undefined : json['inherit_fields_remove_all'],
'childInheritFieldsAdd': json['child_inherit_fields_add'],
'childInheritFieldsRemove': json['child_inherit_fields_remove'],
'childInheritFieldsSet': json['child_inherit_fields_set'],
'childInheritFieldsRemoveAll': json['child_inherit_fields_remove_all'] == null ? undefined : json['child_inherit_fields_remove_all'],
'substituteChildren': json['substitute_children'] == null ? undefined : json['substitute_children'],
'substituteSiblings': json['substitute_siblings'] == null ? undefined : json['substitute_siblings'],
'ignoreShopping': json['ignore_shopping'] == null ? undefined : json['ignore_shopping'],
'onHand': json['on_hand'] == null ? undefined : json['on_hand'],
};
}
export function FoodBatchUpdateToJSON(value?: FoodBatchUpdate | null): any {
if (value == null) {
return value;
}
return {
'foods': value['foods'],
'category': value['category'],
'substitute_add': value['substituteAdd'],
'substitute_remove': value['substituteRemove'],
'substitute_set': value['substituteSet'],
'substitute_remove_all': value['substituteRemoveAll'],
'inherit_fields_add': value['inheritFieldsAdd'],
'inherit_fields_remove': value['inheritFieldsRemove'],
'inherit_fields_set': value['inheritFieldsSet'],
'inherit_fields_remove_all': value['inheritFieldsRemoveAll'],
'child_inherit_fields_add': value['childInheritFieldsAdd'],
'child_inherit_fields_remove': value['childInheritFieldsRemove'],
'child_inherit_fields_set': value['childInheritFieldsSet'],
'child_inherit_fields_remove_all': value['childInheritFieldsRemoveAll'],
'substitute_children': value['substituteChildren'],
'substitute_siblings': value['substituteSiblings'],
'ignore_shopping': value['ignoreShopping'],
'on_hand': value['onHand'],
};
}

View File

@@ -27,6 +27,7 @@ export * from './ExportRequest';
export * from './FdcQuery';
export * from './FdcQueryFoods';
export * from './Food';
export * from './FoodBatchUpdate';
export * from './FoodInheritField';
export * from './FoodShoppingUpdate';
export * from './FoodSimple';

View File

@@ -34,8 +34,8 @@
</v-card-actions>
<v-card-text v-if="genericModel.model.name == 'AiLog'">
{{$t('MonthlyCreditsUsed')}} ({{ useUserPreferenceStore().activeSpace.aiMonthlyCreditsUsed }} / {{ useUserPreferenceStore().activeSpace.aiCreditsMonthly }})
{{$t('AiCreditsBalance')}} : {{useUserPreferenceStore().activeSpace.aiCreditsBalance}}
{{ $t('MonthlyCreditsUsed') }} ({{ useUserPreferenceStore().activeSpace.aiMonthlyCreditsUsed }} / {{ useUserPreferenceStore().activeSpace.aiCreditsMonthly }})
{{ $t('AiCreditsBalance') }} : {{ useUserPreferenceStore().activeSpace.aiCreditsBalance }}
<v-progress-linear :model-value="useUserPreferenceStore().activeSpace.aiMonthlyCreditsUsed" :max="useUserPreferenceStore().activeSpace.aiCreditsMonthly"></v-progress-linear>
</v-card-text>
</v-card>
@@ -65,6 +65,9 @@
<v-icon icon="fa-solid fa-ellipsis-v"></v-icon>
<v-menu activator="parent" close-on-content-click>
<v-list density="compact" class="pt-1 pb-1" activatable>
<v-list-item prepend-icon="fa-solid fa-list-check" @click="batchEditDialog = true" v-if="genericModel.model.name == 'Food'">
{{ $t('BatchEdit') }}
</v-list-item>
<v-list-item prepend-icon="fa-solid fa-arrows-to-dot" @click="batchMergeDialog = true" v-if="genericModel.model.isMerge">
{{ $t('Merge') }}
</v-list-item>
@@ -76,8 +79,8 @@
</v-btn>
</template>
<template v-slot:item.space="{ item }" v-if="genericModel.model.name == 'AiProvider'">
<v-chip label v-if="item.space == null" color="success">{{$t('Global')}}</v-chip>
<v-chip label v-else color="info">{{$t('Space')}}</v-chip>
<v-chip label v-if="item.space == null" color="success">{{ $t('Global') }}</v-chip>
<v-chip label v-else color="info">{{ $t('Space') }}</v-chip>
</template>
<template v-slot:item.action="{ item }">
<v-btn class="float-right" icon="$menu" variant="plain">
@@ -117,10 +120,13 @@
</v-row>
<batch-delete-dialog :items="selectedItems" :model="props.model" v-model="batchDeleteDialog" activator="model"
@change="loadItems({page: page, itemsPerPage: pageSize, search: query})"></batch-delete-dialog>
@change="loadItems({page: page, itemsPerPage: pageSize, search: query})"></batch-delete-dialog>
<model-merge-dialog :model="model" :source="selectedItems" v-model="batchMergeDialog" activator="model"
@change="loadItems({page: page, itemsPerPage: pageSize, search: query})"></model-merge-dialog>
<model-merge-dialog :model="model" :source="selectedItems" v-model="batchMergeDialog" activator="model"
@change="loadItems({page: page, itemsPerPage: pageSize, search: query})"></model-merge-dialog>
<batch-edit-food-dialog :items="selectedItems" v-model="batchEditDialog" v-if="model == 'Food'" activator="model"
@change="loadItems({page: page, itemsPerPage: pageSize, search: query})"></batch-edit-food-dialog>
</v-container>
</template>
@@ -144,6 +150,7 @@ import RecipeShareDialog from "@/components/dialogs/RecipeShareDialog.vue";
import AddToShoppingDialog from "@/components/dialogs/AddToShoppingDialog.vue";
import BatchDeleteDialog from "@/components/dialogs/BatchDeleteDialog.vue";
import {useRouteQuery} from "@vueuse/router";
import BatchEditFoodDialog from "@/components/dialogs/BatchEditFoodDialog.vue";
const {t} = useI18n()
const router = useRouter()
@@ -172,6 +179,7 @@ const selectedItems = ref([] as EditorSupportedTypes[])
const batchDeleteDialog = ref(false)
const batchMergeDialog = ref(false)
const batchEditDialog = ref(false)
// data
const loading = ref(false);
@@ -215,7 +223,7 @@ function loadItems(options: VDataTableUpdateOptions) {
page.value = options.page
pageSize.value = options.itemsPerPage
genericModel.value.list({ query: query.value, page: options.page, pageSize: pageSize.value }).then((r: any) => {
genericModel.value.list({query: query.value, page: options.page, pageSize: pageSize.value}).then((r: any) => {
items.value = r.results
itemCount.value = r.count
}).catch((err: any) => {