From a062a4beaa407d5211bf901b28221ad35d1f3314 Mon Sep 17 00:00:00 2001 From: boc-the-git <3479092+boc-the-git@users.noreply.github.com> Date: Sat, 29 Jun 2024 01:16:04 +1000 Subject: [PATCH] feat: Add the ability to flag a food as "on hand", to exclude from shopping list (#3777) --- ...3_32d69327997b_add_staple_flag_to_foods.py | 48 +++++++++++++++++++ .../Recipe/RecipeDialogAddToShoppingList.vue | 2 +- frontend/composables/store/use-food-store.ts | 2 + frontend/lang/messages/en-US.json | 3 +- frontend/lib/api/types/recipe.ts | 4 +- frontend/pages/group/data/foods.vue | 26 ++++++++++ mealie/db/models/recipe/ingredient.py | 25 ++++++++-- mealie/schema/recipe/recipe_ingredient.py | 11 ++++- 8 files changed, 112 insertions(+), 9 deletions(-) create mode 100644 alembic/versions/2024-06-22-10.17.03_32d69327997b_add_staple_flag_to_foods.py diff --git a/alembic/versions/2024-06-22-10.17.03_32d69327997b_add_staple_flag_to_foods.py b/alembic/versions/2024-06-22-10.17.03_32d69327997b_add_staple_flag_to_foods.py new file mode 100644 index 000000000000..65e2d4e02f06 --- /dev/null +++ b/alembic/versions/2024-06-22-10.17.03_32d69327997b_add_staple_flag_to_foods.py @@ -0,0 +1,48 @@ +"""Add staple flag to foods + +Revision ID: 32d69327997b +Revises: 7788478a0338 +Create Date: 2024-06-22 10:17:03.323966 + +""" + +import sqlalchemy as sa +from sqlalchemy import orm + +from alembic import op + + +# revision identifiers, used by Alembic. +revision = "32d69327997b" +down_revision = "7788478a0338" +branch_labels = None +depends_on = None + + +def is_postgres(): + return op.get_context().dialect.name == "postgresql" + + +def upgrade(): + with op.batch_alter_table("ingredient_foods") as batch_op: + batch_op.add_column(sa.Column("on_hand", sa.Boolean(), nullable=True, default=False)) + + bind = op.get_bind() + session = orm.Session(bind=bind) + + with session: + if is_postgres(): + stmt = "UPDATE ingredient_foods SET on_hand = FALSE;" + else: + stmt = "UPDATE ingredient_foods SET on_hand = 0;" + + session.execute(sa.text(stmt)) + + # forbid nulls after migration + with op.batch_alter_table("ingredient_foods") as batch_op: + batch_op.alter_column("on_hand", nullable=False) + + +def downgrade(): + with op.batch_alter_table("ingredient_foods") as batch_op: + batch_op.drop_column("on_hand") diff --git a/frontend/components/Domain/Recipe/RecipeDialogAddToShoppingList.vue b/frontend/components/Domain/Recipe/RecipeDialogAddToShoppingList.vue index 9209b079cc92..89dd45eb115b 100644 --- a/frontend/components/Domain/Recipe/RecipeDialogAddToShoppingList.vue +++ b/frontend/components/Domain/Recipe/RecipeDialogAddToShoppingList.vue @@ -231,7 +231,7 @@ export default defineComponent({ const shoppingListIngredients: ShoppingListIngredient[] = recipe.recipeIngredient.map((ing) => { return { - checked: true, + checked: !ing.food?.onHand, ingredient: ing, disableAmount: recipe.settings?.disableAmount || false, } diff --git a/frontend/composables/store/use-food-store.ts b/frontend/composables/store/use-food-store.ts index ff0fb7711e48..4b02210c382a 100644 --- a/frontend/composables/store/use-food-store.ts +++ b/frontend/composables/store/use-food-store.ts @@ -19,6 +19,7 @@ export const useFoodData = function () { name: "", description: "", labelId: undefined, + onHand: false, }); function reset() { @@ -26,6 +27,7 @@ export const useFoodData = function () { data.name = ""; data.description = ""; data.labelId = undefined; + data.onHand = false; } return { diff --git a/frontend/lang/messages/en-US.json b/frontend/lang/messages/en-US.json index a9f949e5b319..226207109f19 100644 --- a/frontend/lang/messages/en-US.json +++ b/frontend/lang/messages/en-US.json @@ -988,7 +988,8 @@ "food-data": "Food Data", "example-food-singular": "ex: Onion", "example-food-plural": "ex: Onions", - "label-overwrite-warning": "This will assign the chosen label to all selected foods and potentially overwrite your existing labels." + "label-overwrite-warning": "This will assign the chosen label to all selected foods and potentially overwrite your existing labels.", + "on-hand-checkbox-label": "Setting this flag will make this food unchecked by default when adding a recipe to a shopping list." }, "units": { "seed-dialog-text": "Seed the database with common units based on your local language.", diff --git a/frontend/lib/api/types/recipe.ts b/frontend/lib/api/types/recipe.ts index 23189db60119..8085948eab7b 100644 --- a/frontend/lib/api/types/recipe.ts +++ b/frontend/lib/api/types/recipe.ts @@ -63,6 +63,7 @@ export interface CreateIngredientFood { }; labelId?: string; aliases?: CreateIngredientFoodAlias[]; + onHand?: boolean; } export interface CreateIngredientFoodAlias { name: string; @@ -135,6 +136,7 @@ export interface IngredientFood { label?: MultiPurposeLabelSummary; createdAt?: string; updateAt?: string; + onHand?: boolean; } export interface IngredientFoodAlias { name: string; @@ -464,7 +466,7 @@ export interface ScrapeRecipe { export interface ScrapeRecipeTest { url: string; } -export interface SlugResponse {} +export interface SlugResponse { } export interface TagIn { name: string; } diff --git a/frontend/pages/group/data/foods.vue b/frontend/pages/group/data/foods.vue index cf0ad1f6ab2c..290b7dcef8e3 100644 --- a/frontend/pages/group/data/foods.vue +++ b/frontend/pages/group/data/foods.vue @@ -87,6 +87,14 @@ :label="$t('data-pages.foods.food-label')" > + +

+ {{ $t("data-pages.foods.on-hand-checkbox-label") }} +

@@ -134,6 +142,14 @@ :label="$t('data-pages.foods.food-label')" > + +

+ {{ $t("data-pages.foods.on-hand-checkbox-label") }} +

+