mirror of
https://github.com/TandoorRecipes/recipes.git
synced 2025-12-31 20:00:38 -05:00
Compare commits
19 Commits
feature/sh
...
dependabot
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7a72535fe4 | ||
|
|
28e554d04b | ||
|
|
5040caf91c | ||
|
|
c5fcfd07a7 | ||
|
|
a1a172e223 | ||
|
|
0039654d40 | ||
|
|
17de37b9fc | ||
|
|
d0856ce3b7 | ||
|
|
24426c2b7e | ||
|
|
5380b7d697 | ||
|
|
1d0488fbb0 | ||
|
|
2213346297 | ||
|
|
126f21842f | ||
|
|
84898b09f2 | ||
|
|
d4ded02c2a | ||
|
|
8db294255e | ||
|
|
c99d13e2e7 | ||
|
|
59040f4cdf | ||
|
|
af476480c1 |
4
.github/workflows/ci.yml
vendored
4
.github/workflows/ci.yml
vendored
@@ -31,7 +31,7 @@ jobs:
|
||||
pip install -r requirements.txt
|
||||
|
||||
- name: Cache StaticFiles
|
||||
uses: actions/cache@v4
|
||||
uses: actions/cache@v5
|
||||
id: django_cache
|
||||
with:
|
||||
path: |
|
||||
@@ -64,7 +64,7 @@ jobs:
|
||||
run: |
|
||||
python3 manage.py collectstatic --noinput
|
||||
|
||||
- uses: actions/cache/save@v4
|
||||
- uses: actions/cache/save@v5
|
||||
if: steps.django_cache.outputs.cache-hit != 'true'
|
||||
with:
|
||||
path: |
|
||||
|
||||
@@ -177,8 +177,9 @@ class RecipeShoppingEditor():
|
||||
existing = self._shopping_list_recipe.entries.filter(ingredient__in=ingredients).values_list('ingredient__pk', flat=True)
|
||||
add_ingredients = ingredients.exclude(id__in=existing)
|
||||
|
||||
entries = []
|
||||
for i in [x for x in add_ingredients if x.food]:
|
||||
ShoppingListEntry.objects.create(
|
||||
entry = ShoppingListEntry(
|
||||
list_recipe=self._shopping_list_recipe,
|
||||
food=i.food,
|
||||
unit=i.unit,
|
||||
@@ -187,6 +188,12 @@ class RecipeShoppingEditor():
|
||||
created_by=self.created_by,
|
||||
space=self.space,
|
||||
)
|
||||
entries.append(entry)
|
||||
|
||||
ShoppingListEntry.objects.bulk_create(entries)
|
||||
for e in entries:
|
||||
if e.food.shopping_lists.count() > 0:
|
||||
e.shopping_lists.set(e.food.shopping_lists.all())
|
||||
|
||||
# deletes shopping list entries not in ingredients list
|
||||
def _delete_ingredients(self, ingredients=None):
|
||||
|
||||
@@ -197,7 +197,7 @@ class Mealie1(Integration):
|
||||
space=self.request.space,
|
||||
)
|
||||
ingredients_relation.append(Step.ingredients.through(step_id=get_step_id(i, first_step_of_recipe_dict, step_id_dict,recipe_ingredient_ref_link_dict), ingredient_id=ingredient.pk))
|
||||
elif i['note'].strip():
|
||||
elif i['note'] and i['note'].strip():
|
||||
amount, unit, food, note = ingredient_parser.parse(i['note'].strip())
|
||||
f = ingredient_parser.get_food(food)
|
||||
u = ingredient_parser.get_unit(unit)
|
||||
|
||||
@@ -8,7 +8,7 @@ msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2025-09-22 20:15+0200\n"
|
||||
"PO-Revision-Date: 2025-11-15 12:08+0000\n"
|
||||
"PO-Revision-Date: 2025-12-01 06:08+0000\n"
|
||||
"Last-Translator: \"Matjaž T.\" <matjaz@moj-svet.si>\n"
|
||||
"Language-Team: Slovenian <http://translate.tandoor.dev/projects/tandoor/"
|
||||
"recipes-backend/sl/>\n"
|
||||
@@ -2129,9 +2129,8 @@ msgid ""
|
||||
"please consult the django documentation on how to reset passwords."
|
||||
msgstr ""
|
||||
"Nastavitveno stran lahko uporabite samo za ustvarjanje prvega "
|
||||
"uporabnika! \n"
|
||||
" Če ste pozabili svoje poverilnice superuporabnika, si oglejte "
|
||||
"dokumentacijo django o tem, kako ponastaviti gesla."
|
||||
"uporabnika! Če ste pozabili poverilnice superuporabnika, "
|
||||
"si oglejte dokumentacijo django za ponastavitev gesel."
|
||||
|
||||
#: .\cookbook\views\views.py:304
|
||||
msgid "Passwords dont match!"
|
||||
|
||||
@@ -8,7 +8,7 @@ msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2024-08-01 15:04+0200\n"
|
||||
"PO-Revision-Date: 2025-11-22 20:03+0000\n"
|
||||
"PO-Revision-Date: 2025-12-02 08:03+0000\n"
|
||||
"Last-Translator: SerhiiOS <serhios@users.noreply.translate.tandoor.dev>\n"
|
||||
"Language-Team: Ukrainian <http://translate.tandoor.dev/projects/tandoor/"
|
||||
"recipes-backend/uk/>\n"
|
||||
@@ -468,7 +468,7 @@ msgstr "Пошук"
|
||||
#: .\cookbook\models.py:455 .\cookbook\templates\base.html:114
|
||||
#: .\cookbook\templates\meal_plan.html:7
|
||||
msgid "Meal-Plan"
|
||||
msgstr "План харчування"
|
||||
msgstr "Меню"
|
||||
|
||||
#: .\cookbook\models.py:456 .\cookbook\templates\base.html:122
|
||||
#: .\cookbook\views\views.py:459
|
||||
@@ -2790,7 +2790,7 @@ msgstr ""
|
||||
|
||||
#: .\cookbook\views\views.py:451
|
||||
msgid "Manage recipes, shopping list, meal plans and more."
|
||||
msgstr "Керуйте рецептами, списком покупок, планами харчування тощо."
|
||||
msgstr "Керуйте рецептами, списком покупок, меню тощо."
|
||||
|
||||
#: .\cookbook\views\views.py:458
|
||||
msgid "Plan"
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import traceback
|
||||
import uuid
|
||||
from datetime import datetime, timedelta
|
||||
from decimal import Decimal
|
||||
@@ -188,14 +189,22 @@ class SpaceFilterSerializer(serializers.ListSerializer):
|
||||
else:
|
||||
iterable = data.all() if hasattr(data, 'all') else data
|
||||
if isinstance(iterable, list) or (isinstance(iterable, QuerySet) and getattr(iterable, '_result_cache', None) is not None):
|
||||
data = [d for d in iterable if d.userspace.space.id == self.context['request'].space.id]
|
||||
try:
|
||||
new_data = []
|
||||
for u in iterable:
|
||||
for us in u.userspace_set.all():
|
||||
if us.space.id == self.context['request'].space.id:
|
||||
new_data.append(u)
|
||||
data = new_data
|
||||
except Exception:
|
||||
traceback.print_exc()
|
||||
data = data.filter(userspace__space=self.context['request'].user.get_active_space()).all()
|
||||
else:
|
||||
if hasattr(self.context['request'], 'space'):
|
||||
data = data.filter(userspace__space=self.context['request'].space).all()
|
||||
else:
|
||||
# not sure why but this branch can be hit (just normal page load, need to see why)
|
||||
data = data.filter(userspace__space=self.context['request'].user.get_active_space()).all()
|
||||
|
||||
elif isinstance(data, list):
|
||||
data = [d for d in data if getattr(d, self.child.Meta.model.get_space_key()[0]) == self.context['request'].space]
|
||||
else:
|
||||
@@ -772,7 +781,7 @@ class SupermarketCategoryRelationSerializer(WritableNestedModelSerializer):
|
||||
fields = ('id', 'category', 'supermarket', 'order')
|
||||
|
||||
|
||||
class SupermarketSerializer(UniqueFieldsMixin, SpacedModelSerializer, OpenDataModelMixin):
|
||||
class SupermarketSerializer(UniqueFieldsMixin, SpacedModelSerializer, WritableNestedModelSerializer, OpenDataModelMixin):
|
||||
category_to_supermarket = SupermarketCategoryRelationSerializer(many=True, read_only=True)
|
||||
shopping_lists = ShoppingListSerializer(many=True, required=False)
|
||||
|
||||
@@ -1430,8 +1439,17 @@ class ShoppingListRecipeSerializer(serializers.ModelSerializer):
|
||||
read_only_fields = ('id', 'created_by',)
|
||||
|
||||
|
||||
class FoodShoppingSerializer(serializers.ModelSerializer):
|
||||
supermarket_category = SupermarketCategorySerializer(read_only=True)
|
||||
shopping_lists = ShoppingListSerializer(read_only=True, many=True)
|
||||
|
||||
class Meta:
|
||||
model = Food
|
||||
fields = ('id', 'name', 'plural_name', 'supermarket_category', 'shopping_lists')
|
||||
|
||||
|
||||
class ShoppingListEntrySerializer(WritableNestedModelSerializer):
|
||||
food = FoodSimpleSerializer(allow_null=True)
|
||||
food = FoodShoppingSerializer(allow_null=True)
|
||||
unit = UnitSerializer(allow_null=True, required=False)
|
||||
shopping_lists = ShoppingListSerializer(many=True, required=False)
|
||||
list_recipe_data = ShoppingListRecipeSerializer(source='list_recipe', read_only=True)
|
||||
|
||||
@@ -1992,19 +1992,22 @@ class ShoppingListRecipeViewSet(LoggingMixin, viewsets.ModelViewSet):
|
||||
if serializer.is_valid():
|
||||
entries = []
|
||||
for e in serializer.validated_data['entries']:
|
||||
entries.append(
|
||||
ShoppingListEntry(
|
||||
list_recipe_id=obj.pk,
|
||||
amount=e['amount'],
|
||||
unit_id=e['unit_id'],
|
||||
food_id=e['food_id'],
|
||||
ingredient_id=e['ingredient_id'],
|
||||
created_by_id=request.user.id,
|
||||
space_id=request.space.id,
|
||||
)
|
||||
entry = ShoppingListEntry(
|
||||
list_recipe_id=obj.pk,
|
||||
amount=e['amount'],
|
||||
unit_id=e['unit_id'],
|
||||
food_id=e['food_id'],
|
||||
ingredient_id=e['ingredient_id'],
|
||||
created_by_id=request.user.id,
|
||||
space_id=request.space.id,
|
||||
)
|
||||
entries.append(entry)
|
||||
|
||||
ShoppingListEntry.objects.bulk_create(entries)
|
||||
for e in entries:
|
||||
if e.food.shopping_lists.count() > 0:
|
||||
e.shopping_lists.set(e.food.shopping_lists.all())
|
||||
|
||||
ConnectorManager.add_work(ActionType.CREATED, *entries)
|
||||
return Response(serializer.validated_data)
|
||||
else:
|
||||
@@ -2041,10 +2044,12 @@ class ShoppingListEntryViewSet(LoggingMixin, viewsets.ModelViewSet):
|
||||
def get_queryset(self):
|
||||
self.queryset = self.queryset.filter(space=self.request.space)
|
||||
|
||||
# select_related("list_recipe")
|
||||
self.queryset = self.queryset.filter(
|
||||
Q(created_by=self.request.user)
|
||||
| Q(created_by__in=list(self.request.user.get_shopping_share()))).prefetch_related('created_by',
|
||||
'food',
|
||||
'food__shopping_lists',
|
||||
'shopping_lists',
|
||||
'unit',
|
||||
'list_recipe',
|
||||
@@ -2052,6 +2057,7 @@ class ShoppingListEntryViewSet(LoggingMixin, viewsets.ModelViewSet):
|
||||
'list_recipe__recipe__created_by',
|
||||
'list_recipe__mealplan',
|
||||
'list_recipe__mealplan__shared',
|
||||
'list_recipe__mealplan__shared__userspace_set',
|
||||
'list_recipe__mealplan__shoppinglistrecipe_set',
|
||||
'list_recipe__mealplan__recipe',
|
||||
'list_recipe__mealplan__recipe__keywords',
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Django==5.2.8
|
||||
Django==5.2.9
|
||||
cryptography===45.0.5
|
||||
django-annoying==0.10.6
|
||||
django-cleanup==9.0.0
|
||||
|
||||
@@ -174,6 +174,8 @@ const isShoppingLineDelayed = computed(() => {
|
||||
function categoryUpdate(category: SupermarketCategory) {
|
||||
const api = new ApiApi()
|
||||
shoppingListFood.value.food.supermarketCategory = category
|
||||
shoppingListFood.value.entries.forEach(e => e.food.supermarketCategory = category)
|
||||
useShoppingStore().updateEntriesStructure()
|
||||
api.apiFoodUpdate({id: shoppingListFood.value.food.id, food: shoppingListFood.value.food}).then(r => {
|
||||
useMessageStore().addPreparedMessage(PreparedMessage.UPDATE_SUCCESS)
|
||||
}).catch(err => {
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
<template>
|
||||
<v-list-item class="swipe-container border-t-sm mt-0 mb-0 pt-0 pb-0 pe-0 pa-0 shopping-border" :id="itemContainerId" @touchend="handleSwipe()" @click="dialog = true;"
|
||||
|
||||
<v-list-item class="swipe-container border-t-sm mt-0 mb-0 pt-0 pb-0 pe-0 pa-0 shopping-border"
|
||||
:id="itemContainerId"
|
||||
@touchend="handleSwipe()"
|
||||
@click="dialog = true;"
|
||||
:value="shoppingListFood"
|
||||
>
|
||||
<!-- <div class="swipe-action" :class="{'bg-success': !isChecked , 'bg-warning': isChecked }">-->
|
||||
<!-- <i class="swipe-icon fa-fw fas" :class="{'fa-check': !isChecked , 'fa-cart-plus': isChecked }"></i>-->
|
||||
@@ -34,13 +37,18 @@
|
||||
</div>
|
||||
|
||||
|
||||
<template v-slot:[selectBtnSlot]="{ isSelected, select }" v-if="selectEnabled">
|
||||
<v-list-item-action class="ps-3 pe-3" start>
|
||||
<v-checkbox-btn :model-value="isSelected" @update:model-value="select" @click.native.stop=""></v-checkbox-btn>
|
||||
</v-list-item-action>
|
||||
</template>
|
||||
|
||||
<template v-slot:[checkBtnSlot]>
|
||||
<div class="ps-3 pe-3" @click.native.stop="useShoppingStore().setEntriesCheckedState(entries, !isChecked, true);">
|
||||
<v-btn color="success" size="large"
|
||||
:class="{'btn-success': !isChecked, 'btn-warning': isChecked}" :icon="actionButtonIcon" variant="plain">
|
||||
</v-btn>
|
||||
</div>
|
||||
<!-- <i class="d-print-none fa-fw fas" :class="{'fa-check': !isChecked , 'fa-cart-plus': isChecked }"></i>-->
|
||||
</template>
|
||||
|
||||
<!-- <div class="swipe-action bg-primary justify-content-end">-->
|
||||
@@ -71,9 +79,11 @@ const emit = defineEmits(['clicked'])
|
||||
|
||||
const props = defineProps({
|
||||
shoppingListFood: {type: {} as PropType<IShoppingListFood>, required: true},
|
||||
hideInfoRow: {type: Boolean, default: false}
|
||||
hideInfoRow: {type: Boolean, default: false},
|
||||
selectEnabled: {type: Boolean, default: false}
|
||||
})
|
||||
const checkBtnSlot = ref(useUserPreferenceStore().userSettings.leftHanded ? 'prepend' : 'append')
|
||||
const selectBtnSlot = ref(useUserPreferenceStore().userSettings.leftHanded ? 'append' : 'prepend')
|
||||
|
||||
const dialog = ref(false)
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
<v-divider></v-divider>
|
||||
<v-list-item>
|
||||
<v-select hide-details :items="groupingOptionsItems" v-model="useUserPreferenceStore().deviceSettings.shopping_selected_grouping"
|
||||
@update:modelValue="useShoppingStore().updateEntriesStructure()" :label="$t('GroupBy')">
|
||||
:label="$t('GroupBy')">
|
||||
</v-select>
|
||||
</v-list-item>
|
||||
<v-list-item v-if="useUserPreferenceStore().deviceSettings.shopping_selected_grouping == ShoppingGroupingOptions.CATEGORY">
|
||||
@@ -69,14 +69,14 @@
|
||||
</v-list>
|
||||
</v-menu>
|
||||
|
||||
<!-- <v-btn height="100%" rounded="0" variant="plain">-->
|
||||
<!-- <i class="fa-solid fa-download"></i>-->
|
||||
<!-- <shopping-export-dialog></shopping-export-dialog>-->
|
||||
<!-- </v-btn>-->
|
||||
<!-- <v-btn height="100%" rounded="0" variant="plain">-->
|
||||
<!-- <i class="fa-solid fa-download"></i>-->
|
||||
<!-- <shopping-export-dialog></shopping-export-dialog>-->
|
||||
<!-- </v-btn>-->
|
||||
|
||||
<!-- <v-btn height="100%" rounded="0" variant="plain" @click="useShoppingStore().undoChange()">-->
|
||||
<!-- <i class="fa-solid fa-arrow-rotate-left"></i>-->
|
||||
<!-- </v-btn>-->
|
||||
<!-- <v-btn height="100%" rounded="0" variant="plain" @click="useShoppingStore().undoChange()">-->
|
||||
<!-- <i class="fa-solid fa-arrow-rotate-left"></i>-->
|
||||
<!-- </v-btn>-->
|
||||
|
||||
</v-tabs>
|
||||
|
||||
@@ -116,18 +116,29 @@
|
||||
</v-menu>
|
||||
</v-chip>
|
||||
|
||||
<v-chip label density="compact" variant="outlined" style="max-width: 50%;" :prepend-icon="TShoppingList.icon" append-icon="fa-solid fa-caret-down">
|
||||
<template v-if="useUserPreferenceStore().deviceSettings.shopping_selected_shopping_list.length > 0">
|
||||
{{ shoppingLists.filter(sl => useUserPreferenceStore().deviceSettings.shopping_selected_shopping_list.includes(sl.id)).flatMap(sl => sl.name).join(', ') }}
|
||||
<v-chip label density="compact" class="ms-1" variant="outlined"
|
||||
:color="(useUserPreferenceStore().deviceSettings.shopping_selected_shopping_list.length == 0 ? '' : 'secondary')" :prepend-icon="TShoppingList.icon"
|
||||
append-icon="fa-solid fa-caret-down">
|
||||
<template v-if="useUserPreferenceStore().deviceSettings.shopping_selected_shopping_list.filter(sl => sl != -1).length > 0">
|
||||
{{
|
||||
shoppingLists.filter(sl => useUserPreferenceStore().deviceSettings.shopping_selected_shopping_list.includes(sl.id)).flatMap(sl => sl.name).join(', ')
|
||||
}}
|
||||
</template>
|
||||
<template v-else>{{ $t('ShoppingList') }}</template>
|
||||
|
||||
<v-menu activator="parent" :close-on-content-click="false">
|
||||
<v-list density="compact" v-model:selected="useUserPreferenceStore().deviceSettings.shopping_selected_shopping_list"
|
||||
@update:selected="useShoppingStore().updateEntriesStructure()" select-strategy="leaf">
|
||||
<v-list-item @click="useUserPreferenceStore().deviceSettings.shopping_selected_shopping_list = []; useShoppingStore().updateEntriesStructure()">
|
||||
<v-list density="compact" v-model:selected="useUserPreferenceStore().deviceSettings.shopping_selected_shopping_list" select-strategy="leaf">
|
||||
<v-list-item @click="useUserPreferenceStore().deviceSettings.shopping_selected_shopping_list = [] ">
|
||||
{{ $t('All') }}
|
||||
</v-list-item>
|
||||
<v-list-item :value="-1" @click="useUserPreferenceStore().deviceSettings.shopping_selected_shopping_list = [-1];">
|
||||
<template v-slot:prepend="{ isSelected, select }">
|
||||
<v-list-item-action start>
|
||||
<v-checkbox-btn :model-value="isSelected" @update:model-value="select"></v-checkbox-btn>
|
||||
</v-list-item-action>
|
||||
</template>
|
||||
{{ $t('None') }}
|
||||
</v-list-item>
|
||||
<v-list-item v-for="s in shoppingLists" :key="s.id" :value="s.id">
|
||||
<template v-slot:prepend="{ isSelected, select }">
|
||||
<v-list-item-action start>
|
||||
@@ -165,7 +176,7 @@
|
||||
<v-skeleton-loader type="list-item"></v-skeleton-loader>
|
||||
<v-skeleton-loader type="list-item"></v-skeleton-loader>
|
||||
</v-list>
|
||||
<v-list class="mt-3" density="compact" v-else>
|
||||
<v-list class="mt-3" density="compact" v-model:selected="selectedLines" select-strategy="leaf" v-else>
|
||||
<template v-for="category in useShoppingStore().entriesByGroup" :key="category.name">
|
||||
|
||||
|
||||
@@ -303,14 +314,14 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
|
||||
import {computed, onMounted, ref, toRef} from "vue";
|
||||
import {computed, onMounted, ref, shallowRef, toRef, watch} from "vue";
|
||||
import {useShoppingStore} from "@/stores/ShoppingStore";
|
||||
import {ApiApi, Recipe, ResponseError, ShoppingList, ShoppingListEntry, ShoppingListRecipe, Supermarket} from "@/openapi";
|
||||
import {ErrorMessageType, PreparedMessage, useMessageStore} from "@/stores/MessageStore";
|
||||
import ShoppingLineItem from "@/components/display/ShoppingLineItem.vue";
|
||||
import {useUserPreferenceStore} from "@/stores/UserPreferenceStore";
|
||||
import ModelSelect from "@/components/inputs/ModelSelect.vue";
|
||||
import {ShoppingGroupingOptions} from "@/types/Shopping";
|
||||
import {IShoppingListFood, ShoppingGroupingOptions} from "@/types/Shopping";
|
||||
import {useI18n} from "vue-i18n";
|
||||
import NumberScalerDialog from "@/components/inputs/NumberScalerDialog.vue";
|
||||
import SupermarketEditor from "@/components/model_editors/SupermarketEditor.vue";
|
||||
@@ -332,6 +343,8 @@ const supermarkets = ref([] as Supermarket[])
|
||||
const shoppingLists = ref([] as ShoppingList[])
|
||||
const manualAddRecipe = ref<undefined | Recipe>(undefined)
|
||||
|
||||
const selectedLines = shallowRef([] as IShoppingListFood[])
|
||||
|
||||
/**
|
||||
* VSelect items for shopping list grouping options with localized names
|
||||
*/
|
||||
@@ -343,6 +356,10 @@ const groupingOptionsItems = computed(() => {
|
||||
return items
|
||||
})
|
||||
|
||||
watch(() => useUserPreferenceStore().deviceSettings, () => {
|
||||
useShoppingStore().updateEntriesStructure()
|
||||
}, {deep: true})
|
||||
|
||||
onMounted(() => {
|
||||
addEventListener("visibilitychange", (event) => {
|
||||
useShoppingStore().autoSyncHasFocus = (document.visibilityState === 'visible')
|
||||
|
||||
@@ -377,6 +377,7 @@
|
||||
"NoUnit": "Keine Einheit",
|
||||
"No_ID": "ID nicht gefunden und kann nicht gelöscht werden.",
|
||||
"No_Results": "Keine Ergebnisse",
|
||||
"None": "Keine",
|
||||
"NotFound": "Nicht gefunden",
|
||||
"NotFoundHelp": "Die gesuchte Seite konnte nicht gefunden werden.",
|
||||
"NotInShopping": "{food} befindet sich nicht auf Ihrer Einkaufsliste.",
|
||||
|
||||
@@ -375,6 +375,7 @@
|
||||
"NoUnit": "No Unit",
|
||||
"No_ID": "ID not found, cannot delete.",
|
||||
"No_Results": "No Results",
|
||||
"None": "None",
|
||||
"NotFound": "Not found",
|
||||
"NotFoundHelp": "The page or object you are looking for could not be found.",
|
||||
"NotInShopping": "{food} is not in your shopping list.",
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -31,6 +31,7 @@ models/FdcQueryFoods.ts
|
||||
models/Food.ts
|
||||
models/FoodBatchUpdate.ts
|
||||
models/FoodInheritField.ts
|
||||
models/FoodShopping.ts
|
||||
models/FoodShoppingUpdate.ts
|
||||
models/FoodSimple.ts
|
||||
models/GenericModelReference.ts
|
||||
|
||||
106
vue3/src/openapi/models/FoodShopping.ts
Normal file
106
vue3/src/openapi/models/FoodShopping.ts
Normal file
@@ -0,0 +1,106 @@
|
||||
/* 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';
|
||||
import type { ShoppingList } from './ShoppingList';
|
||||
import {
|
||||
ShoppingListFromJSON,
|
||||
ShoppingListFromJSONTyped,
|
||||
ShoppingListToJSON,
|
||||
} from './ShoppingList';
|
||||
import type { SupermarketCategory } from './SupermarketCategory';
|
||||
import {
|
||||
SupermarketCategoryFromJSON,
|
||||
SupermarketCategoryFromJSONTyped,
|
||||
SupermarketCategoryToJSON,
|
||||
} from './SupermarketCategory';
|
||||
|
||||
/**
|
||||
*
|
||||
* @export
|
||||
* @interface FoodShopping
|
||||
*/
|
||||
export interface FoodShopping {
|
||||
/**
|
||||
*
|
||||
* @type {number}
|
||||
* @memberof FoodShopping
|
||||
*/
|
||||
id?: number;
|
||||
/**
|
||||
*
|
||||
* @type {string}
|
||||
* @memberof FoodShopping
|
||||
*/
|
||||
name: string;
|
||||
/**
|
||||
*
|
||||
* @type {string}
|
||||
* @memberof FoodShopping
|
||||
*/
|
||||
pluralName?: string;
|
||||
/**
|
||||
*
|
||||
* @type {SupermarketCategory}
|
||||
* @memberof FoodShopping
|
||||
*/
|
||||
readonly supermarketCategory: SupermarketCategory;
|
||||
/**
|
||||
*
|
||||
* @type {Array<ShoppingList>}
|
||||
* @memberof FoodShopping
|
||||
*/
|
||||
readonly shoppingLists: Array<ShoppingList>;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a given object implements the FoodShopping interface.
|
||||
*/
|
||||
export function instanceOfFoodShopping(value: object): value is FoodShopping {
|
||||
if (!('name' in value) || value['name'] === undefined) return false;
|
||||
if (!('supermarketCategory' in value) || value['supermarketCategory'] === undefined) return false;
|
||||
if (!('shoppingLists' in value) || value['shoppingLists'] === undefined) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
export function FoodShoppingFromJSON(json: any): FoodShopping {
|
||||
return FoodShoppingFromJSONTyped(json, false);
|
||||
}
|
||||
|
||||
export function FoodShoppingFromJSONTyped(json: any, ignoreDiscriminator: boolean): FoodShopping {
|
||||
if (json == null) {
|
||||
return json;
|
||||
}
|
||||
return {
|
||||
|
||||
'id': json['id'] == null ? undefined : json['id'],
|
||||
'name': json['name'],
|
||||
'pluralName': json['plural_name'] == null ? undefined : json['plural_name'],
|
||||
'supermarketCategory': SupermarketCategoryFromJSON(json['supermarket_category']),
|
||||
'shoppingLists': ((json['shopping_lists'] as Array<any>).map(ShoppingListFromJSON)),
|
||||
};
|
||||
}
|
||||
|
||||
export function FoodShoppingToJSON(value?: Omit<FoodShopping, 'supermarketCategory'|'shoppingLists'> | null): any {
|
||||
if (value == null) {
|
||||
return value;
|
||||
}
|
||||
return {
|
||||
|
||||
'id': value['id'],
|
||||
'name': value['name'],
|
||||
'plural_name': value['pluralName'],
|
||||
};
|
||||
}
|
||||
|
||||
@@ -19,6 +19,12 @@ import {
|
||||
UserFromJSONTyped,
|
||||
UserToJSON,
|
||||
} from './User';
|
||||
import type { FoodShopping } from './FoodShopping';
|
||||
import {
|
||||
FoodShoppingFromJSON,
|
||||
FoodShoppingFromJSONTyped,
|
||||
FoodShoppingToJSON,
|
||||
} from './FoodShopping';
|
||||
import type { ShoppingList } from './ShoppingList';
|
||||
import {
|
||||
ShoppingListFromJSON,
|
||||
@@ -37,12 +43,6 @@ import {
|
||||
UnitFromJSONTyped,
|
||||
UnitToJSON,
|
||||
} from './Unit';
|
||||
import type { FoodSimple } from './FoodSimple';
|
||||
import {
|
||||
FoodSimpleFromJSON,
|
||||
FoodSimpleFromJSONTyped,
|
||||
FoodSimpleToJSON,
|
||||
} from './FoodSimple';
|
||||
|
||||
/**
|
||||
* Adds nested create feature
|
||||
@@ -70,10 +70,10 @@ export interface PatchedShoppingListEntry {
|
||||
shoppingLists?: Array<ShoppingList>;
|
||||
/**
|
||||
*
|
||||
* @type {FoodSimple}
|
||||
* @type {FoodShopping}
|
||||
* @memberof PatchedShoppingListEntry
|
||||
*/
|
||||
food?: FoodSimple;
|
||||
food?: FoodShopping;
|
||||
/**
|
||||
*
|
||||
* @type {Unit}
|
||||
@@ -168,7 +168,7 @@ export function PatchedShoppingListEntryFromJSONTyped(json: any, ignoreDiscrimin
|
||||
'id': json['id'] == null ? undefined : json['id'],
|
||||
'listRecipe': json['list_recipe'] == null ? undefined : json['list_recipe'],
|
||||
'shoppingLists': json['shopping_lists'] == null ? undefined : ((json['shopping_lists'] as Array<any>).map(ShoppingListFromJSON)),
|
||||
'food': json['food'] == null ? undefined : FoodSimpleFromJSON(json['food']),
|
||||
'food': json['food'] == null ? undefined : FoodShoppingFromJSON(json['food']),
|
||||
'unit': json['unit'] == null ? undefined : UnitFromJSON(json['unit']),
|
||||
'amount': json['amount'] == null ? undefined : json['amount'],
|
||||
'order': json['order'] == null ? undefined : json['order'],
|
||||
@@ -193,7 +193,7 @@ export function PatchedShoppingListEntryToJSON(value?: Omit<PatchedShoppingListE
|
||||
'id': value['id'],
|
||||
'list_recipe': value['listRecipe'],
|
||||
'shopping_lists': value['shoppingLists'] == null ? undefined : ((value['shoppingLists'] as Array<any>).map(ShoppingListToJSON)),
|
||||
'food': FoodSimpleToJSON(value['food']),
|
||||
'food': FoodShoppingToJSON(value['food']),
|
||||
'unit': UnitToJSON(value['unit']),
|
||||
'amount': value['amount'],
|
||||
'order': value['order'],
|
||||
|
||||
@@ -19,6 +19,12 @@ import {
|
||||
UserFromJSONTyped,
|
||||
UserToJSON,
|
||||
} from './User';
|
||||
import type { FoodShopping } from './FoodShopping';
|
||||
import {
|
||||
FoodShoppingFromJSON,
|
||||
FoodShoppingFromJSONTyped,
|
||||
FoodShoppingToJSON,
|
||||
} from './FoodShopping';
|
||||
import type { ShoppingList } from './ShoppingList';
|
||||
import {
|
||||
ShoppingListFromJSON,
|
||||
@@ -37,12 +43,6 @@ import {
|
||||
UnitFromJSONTyped,
|
||||
UnitToJSON,
|
||||
} from './Unit';
|
||||
import type { FoodSimple } from './FoodSimple';
|
||||
import {
|
||||
FoodSimpleFromJSON,
|
||||
FoodSimpleFromJSONTyped,
|
||||
FoodSimpleToJSON,
|
||||
} from './FoodSimple';
|
||||
|
||||
/**
|
||||
* Adds nested create feature
|
||||
@@ -70,10 +70,10 @@ export interface ShoppingListEntry {
|
||||
shoppingLists?: Array<ShoppingList>;
|
||||
/**
|
||||
*
|
||||
* @type {FoodSimple}
|
||||
* @type {FoodShopping}
|
||||
* @memberof ShoppingListEntry
|
||||
*/
|
||||
food: FoodSimple | null;
|
||||
food: FoodShopping | null;
|
||||
/**
|
||||
*
|
||||
* @type {Unit}
|
||||
@@ -174,7 +174,7 @@ export function ShoppingListEntryFromJSONTyped(json: any, ignoreDiscriminator: b
|
||||
'id': json['id'] == null ? undefined : json['id'],
|
||||
'listRecipe': json['list_recipe'] == null ? undefined : json['list_recipe'],
|
||||
'shoppingLists': json['shopping_lists'] == null ? undefined : ((json['shopping_lists'] as Array<any>).map(ShoppingListFromJSON)),
|
||||
'food': FoodSimpleFromJSON(json['food']),
|
||||
'food': FoodShoppingFromJSON(json['food']),
|
||||
'unit': json['unit'] == null ? undefined : UnitFromJSON(json['unit']),
|
||||
'amount': json['amount'],
|
||||
'order': json['order'] == null ? undefined : json['order'],
|
||||
@@ -199,7 +199,7 @@ export function ShoppingListEntryToJSON(value?: Omit<ShoppingListEntry, 'listRec
|
||||
'id': value['id'],
|
||||
'list_recipe': value['listRecipe'],
|
||||
'shopping_lists': value['shoppingLists'] == null ? undefined : ((value['shoppingLists'] as Array<any>).map(ShoppingListToJSON)),
|
||||
'food': FoodSimpleToJSON(value['food']),
|
||||
'food': FoodShoppingToJSON(value['food']),
|
||||
'unit': UnitToJSON(value['unit']),
|
||||
'amount': value['amount'],
|
||||
'order': value['order'],
|
||||
|
||||
@@ -29,6 +29,7 @@ export * from './FdcQueryFoods';
|
||||
export * from './Food';
|
||||
export * from './FoodBatchUpdate';
|
||||
export * from './FoodInheritField';
|
||||
export * from './FoodShopping';
|
||||
export * from './FoodShoppingUpdate';
|
||||
export * from './FoodSimple';
|
||||
export * from './GenericModelReference';
|
||||
|
||||
@@ -68,7 +68,6 @@ export const useShoppingStore = defineStore(_STORE_ID, () => {
|
||||
// ordering
|
||||
let undefinedCategoryGroup = structure.categories.get(UNDEFINED_CATEGORY)
|
||||
if (undefinedCategoryGroup != null) {
|
||||
totalFoods.value += undefinedCategoryGroup.foods.size
|
||||
orderedStructure.push(undefinedCategoryGroup)
|
||||
structure.categories.delete(UNDEFINED_CATEGORY)
|
||||
}
|
||||
@@ -235,6 +234,9 @@ export const useShoppingStore = defineStore(_STORE_ID, () => {
|
||||
r.results.forEach((e) => {
|
||||
entries.value.set(e.id!, e)
|
||||
})
|
||||
if(r.results.length > 0){
|
||||
updateEntriesStructure()
|
||||
}
|
||||
currentlyUpdating.value = false
|
||||
}).catch((err: any) => {
|
||||
currentlyUpdating.value = false
|
||||
@@ -444,6 +446,8 @@ export const useShoppingStore = defineStore(_STORE_ID, () => {
|
||||
Promise.allSettled(promises).finally(() => {
|
||||
entries.value = new Map([...entries.value, ...updatedEntries])
|
||||
syncQueueRunning.value = false
|
||||
//TODO proper function to splice/update structure as needed
|
||||
useShoppingStore().updateEntriesStructure()
|
||||
if (itemCheckSyncQueue.value.length > 0) {
|
||||
runSyncQueue(500)
|
||||
}
|
||||
|
||||
@@ -19,8 +19,11 @@ export function isEntryVisible(entry: ShoppingListEntry, deviceSettings: DeviceS
|
||||
entryVisible = false
|
||||
}
|
||||
|
||||
// if no list is selected show all entries
|
||||
// if -1 is selected show entries without shopping lists
|
||||
// otherwise check if at least one of the entries lists is selected
|
||||
if(deviceSettings.shopping_selected_shopping_list.length > 0){
|
||||
if(!deviceSettings.shopping_selected_shopping_list.some(sl => (entry.shoppingLists?.findIndex(eSl => eSl.id == sl) != -1))){
|
||||
if(!(deviceSettings.shopping_selected_shopping_list.includes(-1) && entry.shoppingLists?.length == 0) && !deviceSettings.shopping_selected_shopping_list.some(sl => (entry.shoppingLists?.findIndex(eSl => eSl.id == sl) != -1))){
|
||||
entryVisible = false
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user