diff --git a/cookbook/helper/shopping_helper.py b/cookbook/helper/shopping_helper.py
index 98bfe03fb..7e1fa6c76 100644
--- a/cookbook/helper/shopping_helper.py
+++ b/cookbook/helper/shopping_helper.py
@@ -79,7 +79,7 @@ def list_from_recipe(list_recipe=None, recipe=None, mealplan=None, servings=None
elif ingredients:
ingredients = Ingredient.objects.filter(pk__in=ingredients, space=space)
else:
- ingredients = Ingredient.objects.filter(step__recipe=r, space=space)
+ ingredients = Ingredient.objects.filter(step__recipe=r, food__ignore_shopping=False, space=space)
if exclude_onhand := created_by.userpreference.mealplan_autoexclude_onhand:
ingredients = ingredients.exclude(food__onhand_users__id__in=[x.id for x in shared_users])
@@ -101,9 +101,9 @@ def list_from_recipe(list_recipe=None, recipe=None, mealplan=None, servings=None
if ingredients.filter(food__recipe=x).exists():
for ing in ingredients.filter(food__recipe=x):
if exclude_onhand:
- x_ing = Ingredient.objects.filter(step__recipe=x, space=space).exclude(food__onhand_users__id__in=[x.id for x in shared_users])
+ x_ing = Ingredient.objects.filter(step__recipe=x, food__ignore_shopping=False, space=space).exclude(food__onhand_users__id__in=[x.id for x in shared_users])
else:
- x_ing = Ingredient.objects.filter(step__recipe=x, space=space)
+ x_ing = Ingredient.objects.filter(step__recipe=x, food__ignore_shopping=False, space=space).exclude(food__ignore_shopping=True)
for i in [x for x in x_ing]:
ShoppingListEntry.objects.create(
list_recipe=list_recipe,
diff --git a/cookbook/serializer.py b/cookbook/serializer.py
index 288f0538d..8a5212cdc 100644
--- a/cookbook/serializer.py
+++ b/cookbook/serializer.py
@@ -33,7 +33,7 @@ class ExtendedRecipeMixin(serializers.ModelSerializer):
images = None
image = serializers.SerializerMethodField('get_image')
- numrecipe = serializers.ReadOnlyField(source='count_recipes_test')
+ numrecipe = serializers.ReadOnlyField(source='recipe_count')
def get_fields(self, *args, **kwargs):
fields = super().get_fields(*args, **kwargs)
@@ -58,9 +58,6 @@ class ExtendedRecipeMixin(serializers.ModelSerializer):
if obj.recipe_image:
return MEDIA_URL + obj.recipe_image
- def count_recipes(self, obj):
- return Recipe.objects.filter(**{self.recipe_filter: obj}, space=obj.space).count()
-
class CustomDecimalField(serializers.Field):
"""
@@ -169,6 +166,11 @@ class UserPreferenceSerializer(WritableNestedModelSerializer):
food_inherit_default = FoodInheritFieldSerializer(source='space.food_inherit', many=True, allow_null=True, required=False, read_only=True)
plan_share = UserNameSerializer(many=True, allow_null=True, required=False, read_only=True)
shopping_share = UserNameSerializer(many=True, allow_null=True, required=False)
+ food_children_exist = serializers.SerializerMethodField('get_food_children_exist')
+
+ def get_food_children_exist(self, obj):
+ space = getattr(self.context.get('request', None), 'space', None)
+ return Food.objects.filter(depth__gt=0, space=space).exists()
def create(self, validated_data):
if not validated_data.get('user', None):
@@ -183,7 +185,7 @@ class UserPreferenceSerializer(WritableNestedModelSerializer):
'user', 'theme', 'nav_color', 'default_unit', 'default_page', 'use_fractions', 'use_kj', 'search_style', 'show_recent', 'plan_share',
'ingredient_decimals', 'comments', 'shopping_auto_sync', 'mealplan_autoadd_shopping', 'food_inherit_default', 'default_delay',
'mealplan_autoinclude_related', 'mealplan_autoexclude_onhand', 'shopping_share', 'shopping_recent_days', 'csv_delim', 'csv_prefix',
- 'filter_to_supermarket', 'shopping_add_onhand', 'left_handed'
+ 'filter_to_supermarket', 'shopping_add_onhand', 'left_handed', 'food_children_exist'
)
@@ -429,7 +431,7 @@ class FoodSerializer(UniqueFieldsMixin, WritableNestedModelSerializer, ExtendedR
model = Food
fields = (
'id', 'name', 'description', 'shopping', 'recipe', 'food_onhand', 'supermarket_category',
- 'image', 'parent', 'numchild', 'numrecipe', 'inherit_fields', 'full_name'
+ 'image', 'parent', 'numchild', 'numrecipe', 'inherit_fields', 'full_name', 'ignore_shopping'
)
read_only_fields = ('id', 'numchild', 'parent', 'image', 'numrecipe')
@@ -683,14 +685,15 @@ class ShoppingListRecipeSerializer(serializers.ModelSerializer):
value = Decimal(value)
value = value.quantize(Decimal(1)) if value == value.to_integral() else value.normalize() # strips trailing zero
return (
- obj.name
- or getattr(obj.mealplan, 'title', None)
- or (d := getattr(obj.mealplan, 'date', None)) and ': '.join([obj.mealplan.recipe.name, str(d)])
- or obj.recipe.name
- ) + f' ({value:.2g})'
+ obj.name
+ or getattr(obj.mealplan, 'title', None)
+ or (d := getattr(obj.mealplan, 'date', None)) and ': '.join([obj.mealplan.recipe.name, str(d)])
+ or obj.recipe.name
+ ) + f' ({value:.2g})'
def update(self, instance, validated_data):
- if 'servings' in validated_data:
+ # TODO remove once old shopping list
+ if 'servings' in validated_data and self.context.get('view', None).__class__.__name__ != 'ShoppingListViewSet':
list_from_recipe(
list_recipe=instance,
servings=validated_data['servings'],
diff --git a/cookbook/signals.py b/cookbook/signals.py
index d763b8977..b4a528742 100644
--- a/cookbook/signals.py
+++ b/cookbook/signals.py
@@ -121,11 +121,3 @@ def auto_add_shopping(sender, instance=None, created=False, weak=False, **kwargs
'servings': instance.servings
}
list_recipe = list_from_recipe(**kwargs)
-
-
-# user = self.context['request'].user
-# if user.userpreference.shopping_add_onhand:
-# if checked := validated_data.get('checked', None):
-# instance.food.onhand_users.add(*user.userpreference.shopping_share.all(), user)
-# elif checked == False:
-# instance.food.onhand_users.remove(*user.userpreference.shopping_share.all(), user)
diff --git a/cookbook/templates/shopping_list.html b/cookbook/templates/shopping_list.html
index cfb2cb7fb..2720d5898 100644
--- a/cookbook/templates/shopping_list.html
+++ b/cookbook/templates/shopping_list.html
@@ -834,7 +834,7 @@
this.$http.get('{% url 'api:recipe-detail' 123456 %}'.replace('123456', recipe.id)).then((response) => {
for (let s of response.data.steps) {
for (let i of s.ingredients) {
- if (!i.is_header && i.food !== null && i.food.food_onhand === false) {
+ if (!i.is_header && i.food !== null && !i.food.ignore_food) {
this.shopping_list.entries.push({
'list_recipe': slr.id,
'food': i.food,
diff --git a/cookbook/views/api.py b/cookbook/views/api.py
index 1d5140563..9197f53e8 100644
--- a/cookbook/views/api.py
+++ b/cookbook/views/api.py
@@ -118,7 +118,7 @@ class ExtendedRecipeMixin():
# add a recipe count annotation to the query
# explanation on construction https://stackoverflow.com/a/43771738/15762829
recipe_count = Recipe.objects.filter(**{recipe_filter: OuterRef('id')}, space=space).values(recipe_filter).annotate(count=Count('pk')).values('count')
- queryset = queryset.annotate(recipe_count_test=Coalesce(Subquery(recipe_count), 0))
+ queryset = queryset.annotate(recipe_count=Coalesce(Subquery(recipe_count), 0))
# add a recipe image annotation to the query
image_subquery = Recipe.objects.filter(**{recipe_filter: OuterRef('id')}, space=space).exclude(image__isnull=True).exclude(image__exact='').order_by("?").values('image')[:1]
@@ -400,7 +400,7 @@ class SupermarketCategoryViewSet(viewsets.ModelViewSet, StandardFilterMixin):
permission_classes = [CustomIsUser]
def get_queryset(self):
- self.queryset = self.queryset.filter(space=self.request.space)
+ self.queryset = self.queryset.filter(space=self.request.space).order_by('name')
return super().get_queryset()
diff --git a/vue/src/apps/ModelListView/ModelListView.vue b/vue/src/apps/ModelListView/ModelListView.vue
index 1449acbc0..15ef44a49 100644
--- a/vue/src/apps/ModelListView/ModelListView.vue
+++ b/vue/src/apps/ModelListView/ModelListView.vue
@@ -18,7 +18,7 @@
- {{ this.this_model.name }}
+ {{ $t(this.this_model.name) }}
diff --git a/vue/src/apps/RecipeSearchView/RecipeSearchView.vue b/vue/src/apps/RecipeSearchView/RecipeSearchView.vue
index 7a66b7c4b..48bfb2590 100644
--- a/vue/src/apps/RecipeSearchView/RecipeSearchView.vue
+++ b/vue/src/apps/RecipeSearchView/RecipeSearchView.vue
@@ -1,6 +1,6 @@
-
+
@@ -8,21 +8,15 @@
-
+
-
+
-
+
-
+
@@ -32,18 +26,15 @@
-
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
- {{ $t("Close") }}
-
+ {{ $t("Close") }}
@@ -182,12 +138,8 @@
>
-
- {{ $t("or") }}
+
+ {{ $t("or") }}
{{ $t("and") }}
@@ -226,13 +178,8 @@
>
-
- {{
- $t("or")
- }}
+
+ {{ $t("or") }}
{{ $t("and") }}
@@ -256,13 +203,8 @@
>
-
- {{
- $t("or")
- }}
+
+ {{ $t("or") }}
{{ $t("and") }}
@@ -299,9 +241,7 @@
- {{ $t("Page") }} {{ search.pagination_page }}/{{
- Math.ceil(pagination_count / ui.page_size)
- }}
+ {{ $t("Page") }} {{ search.pagination_page }}/{{ Math.ceil(pagination_count / ui.page_size) }}
{{ $t("Reset") }}
@@ -309,24 +249,18 @@
@@ -337,26 +271,22 @@
diff --git a/vue/src/components/Badges/Shopping.vue b/vue/src/components/Badges/Shopping.vue
index e2db01f6e..a156a46a9 100644
--- a/vue/src/components/Badges/Shopping.vue
+++ b/vue/src/components/Badges/Shopping.vue
@@ -1,5 +1,5 @@
-
+
-
{{ Models["FOOD"].name }}
+
{{ $t(Models["FOOD"].name) }}
-
{{ Models["KEYWORD"].name }}
+
{{ $t(Models["KEYWORD"].name) }}
-
{{ Models["UNIT"].name }}
+
{{ $t(Models["UNIT"].name) }}
-
{{ Models["SUPERMARKET"].name }}
+
{{ $t(Models["SUPERMARKET"].name) }}
-
{{ Models["SHOPPING_CATEGORY"].name }}
+
{{ $t(Models["SHOPPING_CATEGORY"].name) }}
-
{{ Models["AUTOMATION"].name }}
+
{{ $t(Models["AUTOMATION"].name) }}
-
{{ Models["USERFILE"].name }}
+
{{ $t(Models["USERFILE"].name) }}
-
{{ Models["STEP"].name }}
+
{{ $t(Models["STEP"].name) }}
diff --git a/vue/src/components/IngredientComponent.vue b/vue/src/components/IngredientComponent.vue
index 595db720b..b3e9919fe 100644
--- a/vue/src/components/IngredientComponent.vue
+++ b/vue/src/components/IngredientComponent.vue
@@ -34,6 +34,7 @@
-
+
-
+
@@ -100,10 +101,10 @@ export default {
filtered_list = filtered_list.filter((x) => x.list_recipe == this.recipe_list)
}
// how many ShoppingListRecipes are there for this recipe?
- let count_shopping_recipes = [...new Set(filtered_list.map((x) => x.list_recipe))].length
+ let count_shopping_recipes = [...new Set(filtered_list.filter((x) => x.list_recipe))].length
let count_shopping_ingredient = filtered_list.filter((x) => x.ingredient == this.ingredient.id).length
- if (count_shopping_recipes >= 1) {
+ if (count_shopping_recipes >= 1 && this.recipe_list) {
// This recipe is in the shopping list
this.shop = false // don't check any boxes until user selects a shopping list to edit
if (count_shopping_ingredient >= 1) {
@@ -117,7 +118,7 @@ export default {
} else {
// there are not recipes in the shopping list
// set default value
- this.shop = !this.ingredient?.food?.food_onhand && !this.ingredient?.food?.recipe
+ this.shop = !this.ingredient?.food?.food_onhand && !this.ingredient?.food?.recipe && !this.ingredient?.food?.ignore_shopping
this.$emit("add-to-shopping", { item: this.ingredient, add: this.shop })
// mark checked if the food is in the shopping list for this ingredient/recipe
if (count_shopping_ingredient >= 1) {
@@ -135,7 +136,7 @@ export default {
if (this.add_shopping_mode) {
// if we are in add shopping mode (e.g. recipe_shopping_modal) start with all checks marked
// except if on_hand (could be if recipe too?)
- this.shop = !this.ingredient?.food?.food_onhand && !this.ingredient?.food?.recipe
+ this.shop = !this.ingredient?.food?.food_onhand && !this.ingredient?.food?.recipe && !this.ingredient?.food?.ignore_shopping
}
},
},
diff --git a/vue/src/components/Modals/CheckboxInput.vue b/vue/src/components/Modals/CheckboxInput.vue
index a6ee13b3c..8a7bb04b9 100644
--- a/vue/src/components/Modals/CheckboxInput.vue
+++ b/vue/src/components/Modals/CheckboxInput.vue
@@ -1,34 +1,34 @@
- {{label}}
+ {{ label }}
+ {{ help }}
\ No newline at end of file
+
diff --git a/vue/src/components/Modals/GenericModalForm.vue b/vue/src/components/Modals/GenericModalForm.vue
index 6a0981a65..48e429879 100644
--- a/vue/src/components/Modals/GenericModalForm.vue
+++ b/vue/src/components/Modals/GenericModalForm.vue
@@ -2,22 +2,26 @@
- {{ form.title }}
+ {{ form.title }}
+
{{ f.label }}
-
-
-
+
+
+
-
- {{ $t("Cancel") }}
- {{ form.ok_label }}
+
+
+ {{ $t("Cancel") }}
+ {{ form.ok_label }}
+
+
@@ -31,7 +35,7 @@ import { getForm, formFunctions } from "@/utils/utils"
Vue.use(BootstrapVue)
import { ApiApiFactory } from "@/utils/openapi/api"
-import { ApiMixin, StandardToasts, ToastMixin } from "@/utils/utils"
+import { ApiMixin, StandardToasts, ToastMixin, getUserPreference } from "@/utils/utils"
import CheckboxInput from "@/components/Modals/CheckboxInput"
import LookupInput from "@/components/Modals/LookupInput"
import TextInput from "@/components/Modals/TextInput"
@@ -39,10 +43,11 @@ import EmojiInput from "@/components/Modals/EmojiInput"
import ChoiceInput from "@/components/Modals/ChoiceInput"
import FileInput from "@/components/Modals/FileInput"
import SmallText from "@/components/Modals/SmallText"
+import HelpBadge from "@/components/Badges/Help"
export default {
name: "GenericModalForm",
- components: { FileInput, CheckboxInput, LookupInput, TextInput, EmojiInput, ChoiceInput, SmallText },
+ components: { FileInput, CheckboxInput, LookupInput, TextInput, EmojiInput, ChoiceInput, SmallText, HelpBadge },
mixins: [ApiMixin, ToastMixin],
props: {
model: { required: true, type: Object },
@@ -73,6 +78,7 @@ export default {
form: {},
dirty: false,
special_handling: false,
+ show_help: true,
}
},
mounted() {
@@ -83,11 +89,19 @@ export default {
buttonLabel() {
return this.buttons[this.action].label
},
+ showHelp() {
+ if (this.show_help) {
+ return true
+ } else {
+ return undefined
+ }
+ },
},
watch: {
show: function () {
if (this.show) {
this.form = getForm(this.model, this.action, this.item1, this.item2)
+
if (this.form?.form_function) {
this.form = formFunctions[this.form.form_function](this.form)
}
@@ -256,15 +270,33 @@ export default {
let type_match = field?.type == field_type
let checks = true
if (type_match && field?.condition) {
- if (field.condition?.condition === "exists") {
- if ((this.item1[field.condition.field] != undefined) === field.condition.value) {
- checks = true
- } else {
- checks = false
- }
+ const value = this.item1[field?.condition?.field]
+ const preference = getUserPreference(field?.condition?.field)
+ console.log("condition", field?.condition?.condition)
+ switch (field?.condition?.condition) {
+ case "field_exists":
+ if ((value != undefined) === field.condition.value) {
+ checks = true
+ } else {
+ checks = false
+ }
+ break
+ case "preference__array_exists":
+ if (preference?.length > 0 === field.condition.value) {
+ checks = true
+ } else {
+ checks = false
+ }
+ break
+ case "preference_equals":
+ if (preference === field.condition.value) {
+ checks = true
+ } else {
+ checks = false
+ }
+ break
}
}
-
return type_match && checks
},
},
diff --git a/vue/src/components/Modals/LookupInput.vue b/vue/src/components/Modals/LookupInput.vue
index 7f41954ce..fa92f9562 100644
--- a/vue/src/components/Modals/LookupInput.vue
+++ b/vue/src/components/Modals/LookupInput.vue
@@ -19,6 +19,7 @@
@new="addNew"
>
+
{{ help }}
@@ -47,6 +48,7 @@ export default {
class_list: { type: String, default: "mb-3" },
show_label: { type: Boolean, default: true },
clear: { type: Number },
+ help: { type: String, default: undefined },
},
data() {
return {
diff --git a/vue/src/components/Modals/TextInput.vue b/vue/src/components/Modals/TextInput.vue
index 94d5225b8..bd25ebc2d 100644
--- a/vue/src/components/Modals/TextInput.vue
+++ b/vue/src/components/Modals/TextInput.vue
@@ -2,6 +2,8 @@
+ {{ help }}
+ {{ subtitle }}
@@ -14,7 +16,8 @@ export default {
label: { type: String, default: "Text Field" },
value: { type: String, default: "" },
placeholder: { type: String, default: "You Should Add Placeholder Text" },
- show_merge: { type: Boolean, default: false },
+ help: { type: String, default: undefined },
+ subtitle: { type: String, default: undefined },
},
data() {
return {
diff --git a/vue/src/locales/en.json b/vue/src/locales/en.json
index f289a5b32..6758ab6a9 100644
--- a/vue/src/locales/en.json
+++ b/vue/src/locales/en.json
@@ -289,5 +289,10 @@
"remember_hours": "Hours to Remember",
"tree_select": "Use Tree Selection",
"left_handed": "Left-handed mode",
- "left_handed_help": "Will optimize the UI for use with your left hand."
+ "left_handed_help": "Will optimize the UI for use with your left hand.",
+ "OnHand_help": "Food is in inventory and will not be automatically added to a shopping list.",
+ "ignore_shopping_help": "Never add food to the shopping list (e.g. water)",
+ "shopping_category_help": "Supermarkets can be ordered and filtered by Shopping Category according to the layout of the aisles.",
+ "food_recipe_help": "Linking a recipe here will include the linked recipe in any other recipe that use this food",
+ "Foods":"Foods"
}
diff --git a/vue/src/utils/models.js b/vue/src/utils/models.js
index 209f10eae..01a8e720d 100644
--- a/vue/src/utils/models.js
+++ b/vue/src/utils/models.js
@@ -59,7 +59,7 @@ export class Models {
// MODELS - inherits and takes precedence over MODEL_TYPES and ACTIONS
static FOOD = {
- name: i18n.t("Food"), // *OPTIONAL* : parameters will be built model -> model_type -> default
+ name: "Food", // *OPTIONAL* : parameters will be built model -> model_type -> default
apiName: "Food", // *REQUIRED* : the name that is used in api.ts for this model
model_type: this.TREE, // *OPTIONAL* : model specific params for api, if not present will attempt modeltype_create then default_create
paginated: true,
@@ -76,15 +76,17 @@ export class Models {
// REQUIRED: unordered array of fields that can be set during create
create: {
// if not defined partialUpdate will use the same parameters, prepending 'id'
- params: [["name", "description", "recipe", "food_onhand", "supermarket_category", "inherit", "inherit_fields"]],
+ params: [["name", "description", "recipe", "food_onhand", "supermarket_category", "inherit", "inherit_fields", "ignore_shopping"]],
form: {
+ show_help: true,
name: {
form_field: true,
type: "text",
field: "name",
label: i18n.t("Name"),
placeholder: "",
+ subtitle_field: "full_name",
},
description: {
form_field: true,
@@ -99,12 +101,21 @@ export class Models {
field: "recipe",
list: "RECIPE",
label: i18n.t("Recipe"),
+ help_text: i18n.t("food_recipe_help"),
},
- shopping: {
+ onhand: {
form_field: true,
type: "checkbox",
field: "food_onhand",
label: i18n.t("OnHand"),
+ help_text: i18n.t("OnHand_help"),
+ },
+ ignore_shopping: {
+ form_field: true,
+ type: "checkbox",
+ field: "ignore_shopping",
+ label: i18n.t("Ignore_Shopping"),
+ help_text: i18n.t("ignore_shopping_help"),
},
shopping_category: {
form_field: true,
@@ -113,6 +124,7 @@ export class Models {
list: "SHOPPING_CATEGORY",
label: i18n.t("Shopping_Category"),
allow_create: true,
+ help_text: i18n.t("shopping_category_help"),
},
inherit_fields: {
form_field: true,
@@ -121,12 +133,7 @@ export class Models {
field: "inherit_fields",
list: "FOOD_INHERIT_FIELDS",
label: i18n.t("InheritFields"),
- condition: { field: "parent", value: true, condition: "exists" },
- },
- full_name: {
- form_field: true,
- type: "smalltext",
- field: "full_name",
+ condition: { field: "food_children_exist", value: true, condition: "preference_equals" },
},
form_function: "FoodCreateDefault",
},
@@ -136,12 +143,12 @@ export class Models {
},
}
static FOOD_INHERIT_FIELDS = {
- name: i18n.t("FoodInherit"),
+ name: "FoodInherit",
apiName: "FoodInheritField",
}
static KEYWORD = {
- name: i18n.t("Keyword"), // *OPTIONAL: parameters will be built model -> model_type -> default
+ name: "Keyword", // *OPTIONAL: parameters will be built model -> model_type -> default
apiName: "Keyword",
model_type: this.TREE,
paginated: true,
@@ -184,7 +191,7 @@ export class Models {
}
static UNIT = {
- name: i18n.t("Unit"),
+ name: "Unit",
apiName: "Unit",
paginated: true,
create: {
@@ -210,7 +217,7 @@ export class Models {
}
static SHOPPING_LIST = {
- name: i18n.t("Shopping_list"),
+ name: "Shopping_list",
apiName: "ShoppingListEntry",
list: {
params: ["id", "checked", "supermarket", "options"],
@@ -239,7 +246,7 @@ export class Models {
}
static RECIPE_BOOK = {
- name: i18n.t("Recipe_Book"),
+ name: "Recipe_Book",
apiName: "RecipeBook",
create: {
params: [["name", "description", "icon"]],
@@ -269,7 +276,7 @@ export class Models {
}
static SHOPPING_CATEGORY = {
- name: i18n.t("Shopping_Category"),
+ name: "Shopping_Category",
apiName: "SupermarketCategory",
create: {
params: [["name", "description"]],
@@ -293,7 +300,7 @@ export class Models {
}
static SHOPPING_CATEGORY_RELATION = {
- name: i18n.t("Shopping_Category_Relation"),
+ name: "Shopping_Category_Relation",
apiName: "SupermarketCategoryRelation",
create: {
params: [["category", "supermarket", "order"]],
@@ -317,7 +324,7 @@ export class Models {
}
static SUPERMARKET = {
- name: i18n.t("Supermarket"),
+ name: "Supermarket",
apiName: "Supermarket",
ordered_tags: [{ field: "category_to_supermarket", label: "category::name", color: "info" }],
create: {
@@ -360,7 +367,7 @@ export class Models {
}
static AUTOMATION = {
- name: i18n.t("Automation"),
+ name: "Automation",
apiName: "Automation",
paginated: true,
list: {
@@ -423,7 +430,7 @@ export class Models {
}
static RECIPE = {
- name: i18n.t("Recipe"),
+ name: "Recipe",
apiName: "Recipe",
list: {
params: ["query", "keywords", "foods", "units", "rating", "books", "keywordsOr", "foodsOr", "booksOr", "internal", "random", "_new", "page", "pageSize", "options"],
@@ -439,7 +446,7 @@ export class Models {
}
static USER_NAME = {
- name: i18n.t("User"),
+ name: "User",
apiName: "User",
list: {
params: ["filter_list"],
@@ -447,7 +454,7 @@ export class Models {
}
static MEAL_TYPE = {
- name: i18n.t("Meal_Type"),
+ name: "Meal_Type",
apiName: "MealType",
list: {
params: ["filter_list"],
@@ -455,7 +462,7 @@ export class Models {
}
static MEAL_PLAN = {
- name: i18n.t("Meal_Plan"),
+ name: "Meal_Plan",
apiName: "MealPlan",
list: {
params: ["options"],
@@ -463,7 +470,7 @@ export class Models {
}
static USERFILE = {
- name: i18n.t("File"),
+ name: "File",
apiName: "UserFile",
paginated: false,
list: {
@@ -492,13 +499,13 @@ export class Models {
},
}
static USER = {
- name: i18n.t("User"),
+ name: "User",
apiName: "User",
paginated: false,
}
static STEP = {
- name: i18n.t("Step"),
+ name: "Step",
apiName: "Step",
list: {
params: ["recipe", "query", "page", "pageSize", "options"],
diff --git a/vue/src/utils/openapi/api.ts b/vue/src/utils/openapi/api.ts
index 8a8c1cfff..43b5182c0 100644
--- a/vue/src/utils/openapi/api.ts
+++ b/vue/src/utils/openapi/api.ts
@@ -211,10 +211,10 @@ export interface Food {
recipe?: FoodRecipe | null;
/**
*
- * @type {boolean}
+ * @type {string}
* @memberof Food
*/
- food_onhand?: boolean;
+ food_onhand?: string | null;
/**
*
* @type {FoodSupermarketCategory}
@@ -245,6 +245,12 @@ export interface Food {
* @memberof Food
*/
full_name?: string;
+ /**
+ *
+ * @type {boolean}
+ * @memberof Food
+ */
+ ignore_shopping?: boolean;
}
/**
*
@@ -607,10 +613,10 @@ export interface IngredientFood {
recipe?: FoodRecipe | null;
/**
*
- * @type {boolean}
+ * @type {string}
* @memberof IngredientFood
*/
- food_onhand?: boolean;
+ food_onhand?: string | null;
/**
*
* @type {FoodSupermarketCategory}
@@ -641,6 +647,12 @@ export interface IngredientFood {
* @memberof IngredientFood
*/
full_name?: string;
+ /**
+ *
+ * @type {boolean}
+ * @memberof IngredientFood
+ */
+ ignore_shopping?: boolean;
}
/**
*
@@ -1182,7 +1194,7 @@ export interface MealPlanRecipe {
* @type {any}
* @memberof MealPlanRecipe
*/
- image?: any;
+ image?: any | null;
/**
*
* @type {Array}
@@ -1255,6 +1267,12 @@ export interface MealPlanRecipe {
* @memberof MealPlanRecipe
*/
_new?: string;
+ /**
+ *
+ * @type {string}
+ * @memberof MealPlanRecipe
+ */
+ recent?: string;
}
/**
*
@@ -1372,7 +1390,7 @@ export interface Recipe {
* @type {any}
* @memberof Recipe
*/
- image?: any;
+ image?: any | null;
/**
*
* @type {Array}
@@ -1715,25 +1733,25 @@ export interface RecipeNutrition {
* @type {string}
* @memberof RecipeNutrition
*/
- carbohydrates?: string;
+ carbohydrates: string;
/**
*
* @type {string}
* @memberof RecipeNutrition
*/
- fats?: string;
+ fats: string;
/**
*
* @type {string}
* @memberof RecipeNutrition
*/
- proteins?: string;
+ proteins: string;
/**
*
* @type {string}
* @memberof RecipeNutrition
*/
- calories?: string;
+ calories: string;
/**
*
* @type {string}
@@ -1770,7 +1788,7 @@ export interface RecipeOverview {
* @type {any}
* @memberof RecipeOverview
*/
- image?: any;
+ image?: any | null;
/**
*
* @type {Array}
@@ -1843,6 +1861,12 @@ export interface RecipeOverview {
* @memberof RecipeOverview
*/
_new?: string;
+ /**
+ *
+ * @type {string}
+ * @memberof RecipeOverview
+ */
+ recent?: string;
}
/**
*
@@ -1918,12 +1942,6 @@ export interface RecipeSteps {
* @memberof RecipeSteps
*/
name?: string;
- /**
- *
- * @type {string}
- * @memberof RecipeSteps
- */
- type?: RecipeStepsTypeEnum;
/**
*
* @type {string}
@@ -1991,18 +2009,6 @@ export interface RecipeSteps {
*/
numrecipe?: string;
}
-
-/**
- * @export
- * @enum {string}
- */
-export enum RecipeStepsTypeEnum {
- Text = 'TEXT',
- Time = 'TIME',
- File = 'FILE',
- Recipe = 'RECIPE'
-}
-
/**
*
* @export
@@ -2523,12 +2529,6 @@ export interface Step {
* @memberof Step
*/
name?: string;
- /**
- *
- * @type {string}
- * @memberof Step
- */
- type?: StepTypeEnum;
/**
*
* @type {string}
@@ -2596,18 +2596,6 @@ export interface Step {
*/
numrecipe?: string;
}
-
-/**
- * @export
- * @enum {string}
- */
-export enum StepTypeEnum {
- Text = 'TEXT',
- Time = 'TIME',
- File = 'FILE',
- Recipe = 'RECIPE'
-}
-
/**
*
* @export
@@ -2952,6 +2940,12 @@ export interface UserPreference {
* @memberof UserPreference
*/
default_page?: UserPreferenceDefaultPageEnum;
+ /**
+ *
+ * @type {boolean}
+ * @memberof UserPreference
+ */
+ use_fractions?: boolean;
/**
*
* @type {boolean}
@@ -3026,10 +3020,10 @@ export interface UserPreference {
mealplan_autoexclude_onhand?: boolean;
/**
*
- * @type {Array}
+ * @type {Array}
* @memberof UserPreference
*/
- shopping_share?: Array;
+ shopping_share?: Array | null;
/**
*
* @type {number}
@@ -3054,6 +3048,18 @@ export interface UserPreference {
* @memberof UserPreference
*/
filter_to_supermarket?: boolean;
+ /**
+ *
+ * @type {boolean}
+ * @memberof UserPreference
+ */
+ shopping_add_onhand?: boolean;
+ /**
+ *
+ * @type {boolean}
+ * @memberof UserPreference
+ */
+ left_handed?: boolean;
}
/**
diff --git a/vue/src/utils/utils.js b/vue/src/utils/utils.js
index 5d332ee59..f03024ded 100644
--- a/vue/src/utils/utils.js
+++ b/vue/src/utils/utils.js
@@ -156,7 +156,7 @@ export function getUserPreference(pref = undefined) {
return undefined
}
if (pref) {
- return user_preference[pref]
+ return user_preference?.[pref]
}
return user_preference
}
@@ -389,6 +389,8 @@ export function getForm(model, action, item1, item2) {
}
if (value?.form_field) {
value["value"] = item1?.[value?.field] ?? undefined
+ value["help"] = item1?.[value?.help_text_field] ?? value?.help_text ?? undefined
+ value["subtitle"] = item1?.[value?.subtitle_field] ?? value?.subtitle ?? undefined
form.fields.push({
...value,
...{