From 9f8c61a75a72d3affa6b2ee87a72e4a6901b8d0d Mon Sep 17 00:00:00 2001 From: Hayden <64056131+hay-kot@users.noreply.github.com> Date: Thu, 4 Nov 2021 18:15:23 -0800 Subject: [PATCH] fix(backend): :bug: Fix recipe page issues (#778) * fix(backend): :bug: Fix favorite assignment on backend * fix(frontend): :bug: fix printer button on recipe page * style(frontend): :children_crossing: add user feadback on copy of recipe link * fix(frontend): :bug: Fix enableLandscape incorrect bindings to remove duplicate values * feat(frontend): :sparkles: add ingredient copy button for markdown list -[ ] format * feat(frontend): :sparkles: add remove prefix button to bulk entry * fix(frontend): :bug: disable random button when no recipes are present * fix(frontend): :sparkles: fix .zip download error * fix(frontend): :children_crossing: close image dialog on upload/get * fix(frontend): :bug: fix assignment on creation for categories and tags * feat(frontend): :sparkles: Open editor on creation / fix edit button on main screen * fix(frontend): :bug: fix false negative regex match for urls on creationg page * feat(frontend): :children_crossing: provide better user feadback when recipe exists * feat(frontend): :sparkles: lock bulk importer on submit * remove zip from navigation * fix(frontend): :sparkles: rerender recipes on delete Co-authored-by: Hayden K --- frontend/api/class-interfaces/recipes.ts | 15 ++- .../Domain/Recipe/RecipeActionMenu.vue | 1 + .../components/Domain/Recipe/RecipeCard.vue | 2 +- .../Domain/Recipe/RecipeCardSection.vue | 3 +- .../Domain/Recipe/RecipeCategoryTagDialog.vue | 10 +- .../Recipe/RecipeCategoryTagSelector.vue | 5 +- .../Domain/Recipe/RecipeContextMenu.vue | 18 ++- .../Domain/Recipe/RecipeDialogBulkAdd.vue | 35 ++++- .../Domain/Recipe/RecipeImageUploadBtn.vue | 5 +- .../Domain/Recipe/RecipeIngredients.vue | 21 ++- .../Domain/Recipe/RecipePrintView.vue | 125 ++++++++++-------- frontend/components/Layout/AppSidebar.vue | 2 +- frontend/components/Layout/TheSnackbar.vue | 2 +- frontend/components/global/AppButtonCopy.vue | 5 + frontend/composables/use-validators.ts | 8 +- frontend/layouts/default.vue | 8 -- frontend/pages/recipe/_slug/index.vue | 36 +++-- frontend/pages/recipe/create.vue | 28 +++- frontend/pages/recipes/all.vue | 14 +- mealie/core/dependencies/dependencies.py | 17 +++ mealie/core/security.py | 7 +- mealie/db/models/_model_utils/auto_init.py | 10 +- mealie/db/models/users/users.py | 39 +++--- mealie/routes/recipe/__init__.py | 1 + mealie/routes/recipe/recipe_crud_routes.py | 23 +--- mealie/routes/recipe/recipe_export.py | 44 +++++- mealie/routes/users/favorites.py | 2 - 27 files changed, 323 insertions(+), 163 deletions(-) diff --git a/frontend/api/class-interfaces/recipes.ts b/frontend/api/class-interfaces/recipes.ts index 175ca78b1b2e..2aa3525731a0 100644 --- a/frontend/api/class-interfaces/recipes.ts +++ b/frontend/api/class-interfaces/recipes.ts @@ -17,7 +17,8 @@ const routes = { recipesParseIngredients: `${prefix}/parser/ingredients`, recipesRecipeSlug: (recipe_slug: string) => `${prefix}/recipes/${recipe_slug}`, - recipesRecipeSlugZip: (recipe_slug: string) => `${prefix}/recipes/${recipe_slug}/zip`, + recipesRecipeSlugExport: (recipe_slug: string) => `${prefix}/recipes/${recipe_slug}/exports`, + recipesRecipeSlugExportZip: (recipe_slug: string) => `${prefix}/recipes/${recipe_slug}/exports/zip`, recipesRecipeSlugImage: (recipe_slug: string) => `${prefix}/recipes/${recipe_slug}/image`, recipesRecipeSlugAssets: (recipe_slug: string) => `${prefix}/recipes/${recipe_slug}/assets`, @@ -72,6 +73,10 @@ export interface BulkCreatePayload { imports: BulkCreateRecipe[]; } +export interface RecipeZipToken { + token: string; +} + export class RecipeAPI extends BaseCRUDAPI { baseRoute: string = routes.recipesBase; itemRoute = routes.recipesRecipeSlug; @@ -151,4 +156,12 @@ export class RecipeAPI extends BaseCRUDAPI { parser = parser || "nlp"; return await this.requests.post(routes.recipesParseIngredient, { parser, ingredient }); } + + async getZipToken(recipeSlug: string) { + return await this.requests.post(routes.recipesRecipeSlugExport(recipeSlug), {}); + } + + getZipRedirectUrl(recipeSlug: string, token: string) { + return `${routes.recipesRecipeSlugExportZip(recipeSlug)}?token=${token}`; + } } diff --git a/frontend/components/Domain/Recipe/RecipeActionMenu.vue b/frontend/components/Domain/Recipe/RecipeActionMenu.vue index 8829121cefe3..c165cdde3f6c 100644 --- a/frontend/components/Domain/Recipe/RecipeActionMenu.vue +++ b/frontend/components/Domain/Recipe/RecipeActionMenu.vue @@ -49,6 +49,7 @@ fab color="info" :card-menu="false" + @print="$emit('print')" />
diff --git a/frontend/components/Domain/Recipe/RecipeCard.vue b/frontend/components/Domain/Recipe/RecipeCard.vue index e1c0ebd0c8a5..a25baeca5b26 100644 --- a/frontend/components/Domain/Recipe/RecipeCard.vue +++ b/frontend/components/Domain/Recipe/RecipeCard.vue @@ -28,7 +28,7 @@ - + diff --git a/frontend/components/Domain/Recipe/RecipeCardSection.vue b/frontend/components/Domain/Recipe/RecipeCardSection.vue index 2019dd8717b0..cc65f68946eb 100644 --- a/frontend/components/Domain/Recipe/RecipeCardSection.vue +++ b/frontend/components/Domain/Recipe/RecipeCardSection.vue @@ -6,7 +6,7 @@ {{ title }} - + {{ $globals.icons.diceMultiple }} @@ -66,6 +66,7 @@ :rating="recipe.rating" :image="recipe.image" :tags="recipe.tags" + @deleted="$emit('deleted', $event)" /> diff --git a/frontend/components/Domain/Recipe/RecipeCategoryTagDialog.vue b/frontend/components/Domain/Recipe/RecipeCategoryTagDialog.vue index 0dd9e3ffa01b..ea4cb9a1d720 100644 --- a/frontend/components/Domain/Recipe/RecipeCategoryTagDialog.vue +++ b/frontend/components/Domain/Recipe/RecipeCategoryTagDialog.vue @@ -93,14 +93,16 @@ export default defineComponent({ async select() { const newItem = await (async () => { if (this.tagDialog) { - const newItem = await this.api.tags.createOne({ name: this.itemName }); - return newItem; + const { data } = await this.api.tags.createOne({ name: this.itemName }); + return data; } else { - const newItem = await this.api.categories.createOne({ name: this.itemName }); - return newItem; + const { data } = await this.api.categories.createOne({ name: this.itemName }); + return data; } })(); + console.log(newItem); + this.$emit(CREATED_ITEM_EVENT, newItem); this.dialog = false; }, diff --git a/frontend/components/Domain/Recipe/RecipeCategoryTagSelector.vue b/frontend/components/Domain/Recipe/RecipeCategoryTagSelector.vue index 96d2314ce6a6..c1aea5e786a5 100644 --- a/frontend/components/Domain/Recipe/RecipeCategoryTagSelector.vue +++ b/frontend/components/Domain/Recipe/RecipeCategoryTagSelector.vue @@ -98,7 +98,7 @@ export default { getAllCategories(); getAllTags(); - return { api, allTags, allCategories }; + return { api, allTags, allCategories, getAllCategories, getAllTags }; }, data() { @@ -152,6 +152,9 @@ export default { }, pushToItem(createdItem) { createdItem = this.returnObject ? createdItem : createdItem.name; + // TODO: Remove excessive get calls + this.getAllCategories(); + this.getAllTags(); this.selected.push(createdItem); }, }, diff --git a/frontend/components/Domain/Recipe/RecipeContextMenu.vue b/frontend/components/Domain/Recipe/RecipeContextMenu.vue index 766964a3dab9..f0f2069818cf 100644 --- a/frontend/components/Domain/Recipe/RecipeContextMenu.vue +++ b/frontend/components/Domain/Recipe/RecipeContextMenu.vue @@ -43,6 +43,7 @@