From 327da02fc8fccf54645e913fb52e0ca16ff1efe7 Mon Sep 17 00:00:00 2001 From: Michael Genson <71845777+michael-genson@users.noreply.github.com> Date: Wed, 20 Nov 2024 08:46:27 -0600 Subject: [PATCH] feat: Structured Yields (#4489) Co-authored-by: Kuchenpirat <24235032+Kuchenpirat@users.noreply.github.com> --- ...4631_add_summary_to_recipe_instructions.py | 1 - ..._b1020f328e98_add_recipe_yield_quantity.py | 72 ++++++++++ .../Domain/Recipe/RecipeDataTable.vue | 12 +- .../Domain/Recipe/RecipeLastMade.vue | 14 +- .../Domain/Recipe/RecipePage/RecipePage.vue | 16 +-- .../RecipePageParts/RecipePageHeader.vue | 51 +------ .../RecipePageParts/RecipePageInfoCard.vue | 101 ++++++++++++++ .../RecipePageInfoCardImage.vue | 69 +++++++++ .../RecipePageParts/RecipePageInfoEditor.vue | 107 ++++++++++++++ .../RecipePageParts/RecipePageScale.vue | 36 +---- .../RecipePageTitleContent.vue | 92 ------------ .../Domain/Recipe/RecipePrintView.vue | 53 ++++++- .../Domain/Recipe/RecipeScaleEditButton.vue | 94 ++++++++----- .../Domain/Recipe/RecipeTimeCard.vue | 60 ++++++-- .../components/Domain/Recipe/RecipeYield.vue | 69 +++++++++ .../use-extract-recipe-yield.test.ts | 111 --------------- .../recipe-page/use-extract-recipe-yield.ts | 132 ------------------ .../recipes/use-scaled-amount.test.ts | 68 +++++++++ .../composables/recipes/use-scaled-amount.ts | 32 +++++ frontend/lang/messages/en-US.json | 5 + frontend/lib/api/types/admin.ts | 2 + frontend/lib/api/types/cookbook.ts | 2 + frontend/lib/api/types/meal-plan.ts | 2 + frontend/lib/api/types/recipe.ts | 4 + frontend/pages/group/data/recipes.vue | 6 +- mealie/db/models/recipe/recipe.py | 8 +- mealie/lang/messages/en-US.json | 8 ++ mealie/lang/providers.py | 6 + mealie/pkgs/i18n/provider_factory.py | 7 +- mealie/routes/spa/__init__.py | 2 +- mealie/schema/recipe/recipe.py | 6 + mealie/services/migrations/tandoor.py | 6 +- .../parser_services/_helpers/string_utils.py | 23 --- .../services/parser_services/brute/process.py | 2 +- .../parser_services/crfpp/pre_processor.py | 22 +-- .../{_helpers => parser_utils}/__init__.py | 0 .../parser_utils/string_utils.py | 111 +++++++++++++++ mealie/services/scraper/cleaner.py | 67 +++++++-- .../scraper_tests/test_cleaner_parts.py | 90 +++++++++++- 39 files changed, 1018 insertions(+), 551 deletions(-) create mode 100644 alembic/versions/2024-10-23-15.50.59_b1020f328e98_add_recipe_yield_quantity.py create mode 100644 frontend/components/Domain/Recipe/RecipePage/RecipePageParts/RecipePageInfoCard.vue create mode 100644 frontend/components/Domain/Recipe/RecipePage/RecipePageParts/RecipePageInfoCardImage.vue create mode 100644 frontend/components/Domain/Recipe/RecipePage/RecipePageParts/RecipePageInfoEditor.vue delete mode 100644 frontend/components/Domain/Recipe/RecipePage/RecipePageParts/RecipePageTitleContent.vue create mode 100644 frontend/components/Domain/Recipe/RecipeYield.vue delete mode 100644 frontend/composables/recipe-page/use-extract-recipe-yield.test.ts delete mode 100644 frontend/composables/recipe-page/use-extract-recipe-yield.ts create mode 100644 frontend/composables/recipes/use-scaled-amount.test.ts create mode 100644 frontend/composables/recipes/use-scaled-amount.ts delete mode 100644 mealie/services/parser_services/_helpers/string_utils.py rename mealie/services/parser_services/{_helpers => parser_utils}/__init__.py (100%) create mode 100644 mealie/services/parser_services/parser_utils/string_utils.py diff --git a/alembic/versions/2024-10-20-09.47.46_3897397b4631_add_summary_to_recipe_instructions.py b/alembic/versions/2024-10-20-09.47.46_3897397b4631_add_summary_to_recipe_instructions.py index f5b6d73ba..1175ca6ef 100644 --- a/alembic/versions/2024-10-20-09.47.46_3897397b4631_add_summary_to_recipe_instructions.py +++ b/alembic/versions/2024-10-20-09.47.46_3897397b4631_add_summary_to_recipe_instructions.py @@ -8,7 +8,6 @@ Create Date: 2024-10-20 09:47:46.844436 import sqlalchemy as sa -import mealie.db.migration_types from alembic import op # revision identifiers, used by Alembic. diff --git a/alembic/versions/2024-10-23-15.50.59_b1020f328e98_add_recipe_yield_quantity.py b/alembic/versions/2024-10-23-15.50.59_b1020f328e98_add_recipe_yield_quantity.py new file mode 100644 index 000000000..4aee9ab79 --- /dev/null +++ b/alembic/versions/2024-10-23-15.50.59_b1020f328e98_add_recipe_yield_quantity.py @@ -0,0 +1,72 @@ +"""add recipe yield quantity + +Revision ID: b1020f328e98 +Revises: 3897397b4631 +Create Date: 2024-10-23 15:50:59.888793 + +""" + +import sqlalchemy as sa +from sqlalchemy import orm + +from alembic import op +from mealie.db.models._model_utils.guid import GUID +from mealie.services.scraper.cleaner import clean_yield + +# revision identifiers, used by Alembic. +revision = "b1020f328e98" +down_revision: str | None = "3897397b4631" +branch_labels: str | tuple[str, ...] | None = None +depends_on: str | tuple[str, ...] | None = None + + +# Intermediate table definitions +class SqlAlchemyBase(orm.DeclarativeBase): + pass + + +class RecipeModel(SqlAlchemyBase): + __tablename__ = "recipes" + + id: orm.Mapped[GUID] = orm.mapped_column(GUID, primary_key=True, default=GUID.generate) + recipe_yield: orm.Mapped[str | None] = orm.mapped_column(sa.String) + recipe_yield_quantity: orm.Mapped[float] = orm.mapped_column(sa.Float, index=True, default=0) + recipe_servings: orm.Mapped[float] = orm.mapped_column(sa.Float, index=True, default=0) + + +def parse_recipe_yields(): + bind = op.get_bind() + session = orm.Session(bind=bind) + + for recipe in session.query(RecipeModel).all(): + try: + recipe.recipe_servings, recipe.recipe_yield_quantity, recipe.recipe_yield = clean_yield(recipe.recipe_yield) + except Exception: + recipe.recipe_servings = 0 + recipe.recipe_yield_quantity = 0 + + session.commit() + + +def upgrade(): + # ### commands auto generated by Alembic - please adjust! ### + with op.batch_alter_table("recipes", schema=None) as batch_op: + batch_op.add_column(sa.Column("recipe_yield_quantity", sa.Float(), nullable=False, server_default="0")) + batch_op.create_index(batch_op.f("ix_recipes_recipe_yield_quantity"), ["recipe_yield_quantity"], unique=False) + batch_op.add_column(sa.Column("recipe_servings", sa.Float(), nullable=False, server_default="0")) + batch_op.create_index(batch_op.f("ix_recipes_recipe_servings"), ["recipe_servings"], unique=False) + + # ### end Alembic commands ### + + parse_recipe_yields() + + +def downgrade(): + # ### commands auto generated by Alembic - please adjust! ### + with op.batch_alter_table("recipes", schema=None) as batch_op: + batch_op.drop_index(batch_op.f("ix_recipes_recipe_servings")) + batch_op.drop_column("recipe_servings") + batch_op.drop_index(batch_op.f("ix_recipes_recipe_yield_quantity")) + batch_op.drop_column("recipe_yield_quantity") + + # ### end Alembic commands ### diff --git a/frontend/components/Domain/Recipe/RecipeDataTable.vue b/frontend/components/Domain/Recipe/RecipeDataTable.vue index a7098466f..fbac4c101 100644 --- a/frontend/components/Domain/Recipe/RecipeDataTable.vue +++ b/frontend/components/Domain/Recipe/RecipeDataTable.vue @@ -63,6 +63,8 @@ interface ShowHeaders { tags: boolean; categories: boolean; tools: boolean; + recipeServings: boolean; + recipeYieldQuantity: boolean; recipeYield: boolean; dateAdded: boolean; } @@ -93,6 +95,8 @@ export default defineComponent({ owner: false, tags: true, categories: true, + recipeServings: true, + recipeYieldQuantity: true, recipeYield: true, dateAdded: true, }; @@ -127,8 +131,14 @@ export default defineComponent({ if (props.showHeaders.tools) { hdrs.push({ text: i18n.t("tool.tools"), value: "tools" }); } + if (props.showHeaders.recipeServings) { + hdrs.push({ text: i18n.t("recipe.servings"), value: "recipeServings" }); + } + if (props.showHeaders.recipeYieldQuantity) { + hdrs.push({ text: i18n.t("recipe.yield"), value: "recipeYieldQuantity" }); + } if (props.showHeaders.recipeYield) { - hdrs.push({ text: i18n.t("recipe.yield"), value: "recipeYield" }); + hdrs.push({ text: i18n.t("recipe.yield-text"), value: "recipeYield" }); } if (props.showHeaders.dateAdded) { hdrs.push({ text: i18n.t("general.date-added"), value: "dateAdded" }); diff --git a/frontend/components/Domain/Recipe/RecipeLastMade.vue b/frontend/components/Domain/Recipe/RecipeLastMade.vue index 9cbe30283..d60de97b4 100644 --- a/frontend/components/Domain/Recipe/RecipeLastMade.vue +++ b/frontend/components/Domain/Recipe/RecipeLastMade.vue @@ -86,12 +86,6 @@