diff --git a/docs/docs/changelog/v1.0.0.md b/docs/docs/changelog/v1.0.0.md index d527a6768..28c92fa13 100644 --- a/docs/docs/changelog/v1.0.0.md +++ b/docs/docs/changelog/v1.0.0.md @@ -47,6 +47,8 @@ **Recipe General** - Recipes are now only viewable by group members +- Recipes now have a `tools` attributes that contains a list of required tools/equipment for the recipe. Tools can be set with a state to determine if you have that tool or not. If it's marked as on hand it will show checked by default. +- Recipe Extras now only show when advanced mode it toggled on - You can now import multiple URLs at a time pre-tagged using the bulk importer. This task runs in the background so no need to wait for it to finish. - Foods/Units for Ingredients are now supported (toggle inside your recipe settings) - Common Food and Units come pre-packaged with Mealie @@ -72,6 +74,7 @@ - Can now be merged with the above step automatically through the action menu - Recipe Ingredients can be linked directly to recipe instructions for improved display - There is an option in the linking dialog to automatically link ingredients. This works by using a key-word matching algorithm to find the ingredients. It's not perfect so you'll need to verify the links after use, additionally you will find that it doesn't work for non-english languages. +- Recipe Instructions now have a preview tab to show the rendered markdown before saving. ### ⚠️ Other things to know... - Themes have been depreciated for specific users. You can still set specific themes for your site through ENV variables. This approach should yield much better results for performance and some weirdness users have experienced. diff --git a/frontend/api/class-interfaces/recipes/index.ts b/frontend/api/class-interfaces/recipes/index.ts new file mode 100644 index 000000000..f10380448 --- /dev/null +++ b/frontend/api/class-interfaces/recipes/index.ts @@ -0,0 +1 @@ +export { RecipeAPI } from "./recipe"; diff --git a/frontend/api/class-interfaces/recipes/recipe-comments.ts b/frontend/api/class-interfaces/recipes/recipe-comments.ts new file mode 100644 index 000000000..c942b6c53 --- /dev/null +++ b/frontend/api/class-interfaces/recipes/recipe-comments.ts @@ -0,0 +1,19 @@ +import { RecipeComment, RecipeCommentCreate } from "./types"; +import { BaseCRUDAPI } from "~/api/_base"; + +const prefix = "/api"; + +const routes = { + comment: `${prefix}/comments`, + byRecipe: (id: string) => `${prefix}/recipes/${id}/comments`, + commentsId: (id: string) => `${prefix}/comments/${id}`, +}; + +export class CommentsApi extends BaseCRUDAPI { + baseRoute: string = routes.comment; + itemRoute = routes.commentsId; + + async byRecipe(slug: string) { + return await this.requests.get(routes.byRecipe(slug)); + } +} diff --git a/frontend/api/class-interfaces/recipes.ts b/frontend/api/class-interfaces/recipes/recipe.ts similarity index 71% rename from frontend/api/class-interfaces/recipes.ts rename to frontend/api/class-interfaces/recipes/recipe.ts index 8eb597389..170a5a62b 100644 --- a/frontend/api/class-interfaces/recipes.ts +++ b/frontend/api/class-interfaces/recipes/recipe.ts @@ -1,7 +1,9 @@ -import { BaseCRUDAPI } from "../_base"; -import { Category } from "./categories"; -import { Tag } from "./tags"; +import { CreateAsset, ParsedIngredient, Parser, RecipeZipToken, BulkCreatePayload } from "./types"; +import { CommentsApi } from "./recipe-comments"; +import { BaseCRUDAPI } from "~/api/_base"; + import { Recipe, CreateRecipe } from "~/types/api-types/recipe"; +import { ApiRequestInstance } from "~/types/api"; const prefix = "/api"; @@ -26,68 +28,35 @@ const routes = { recipesSlugCommentsId: (slug: string, id: number) => `${prefix}/recipes/${slug}/comments/${id}`, }; -export type Parser = "nlp" | "brute"; - -export interface Confidence { - average?: number; - comment?: number; - name?: number; - unit?: number; - quantity?: number; - food?: number; -} - -export interface Unit { - name: string; - description: string; - fraction: boolean; - abbreviation: string; -} - -export interface Food { - name: string; - description?: string; -} - -export interface Ingredient { - referenceId: string; - title: string; - note: string; - unit: Unit | null; - food: Food | null; - disableAmount: boolean; - quantity: number; -} - -export interface ParsedIngredient { - confidence: Confidence; - ingredient: Ingredient; -} - -export interface BulkCreateRecipe { - url: string; - categories: Category[]; - tags: Tag[]; -} - -export interface BulkCreatePayload { - imports: BulkCreateRecipe[]; -} - -export interface RecipeZipToken { - token: string; -} - export class RecipeAPI extends BaseCRUDAPI { baseRoute: string = routes.recipesBase; itemRoute = routes.recipesRecipeSlug; + public comments: CommentsApi; + + constructor(requests: ApiRequestInstance) { + super(requests); + + this.comments = new CommentsApi(requests); + } + async getAllByCategory(categories: string[]) { return await this.requests.get(routes.recipesCategory, { categories, }); } + async createAsset(recipeSlug: string, payload: CreateAsset) { + const formData = new FormData(); + // @ts-ignore + formData.append("file", payload.file); + formData.append("name", payload.name); + formData.append("extension", payload.extension); + formData.append("icon", payload.icon); + + return await this.requests.post(routes.recipesRecipeSlugAssets(recipeSlug), formData); + } + updateImage(slug: string, fileObject: File) { const formData = new FormData(); formData.append("image", fileObject); @@ -113,8 +82,6 @@ export class RecipeAPI extends BaseCRUDAPI { return await this.requests.post(routes.recipesCreateUrlBulk, payload); } - // Recipe Comments - // Methods to Generate reference urls for assets/images * recipeImage(recipeSlug: string, version = null, key = null) { return `/api/media/recipes/${recipeSlug}/images/original.webp?&rnd=${key}&version=${version}`; @@ -132,22 +99,6 @@ export class RecipeAPI extends BaseCRUDAPI { return `/api/media/recipes/${recipeSlug}/assets/${assetName}`; } - async createComment(slug: string, payload: Object) { - return await this.requests.post(routes.recipesSlugComments(slug), payload); - } - - /** Update comment in the Database - */ - async updateComment(slug: string, id: number, payload: Object) { - return await this.requests.put(routes.recipesSlugCommentsId(slug, id), payload); - } - - /** Delete comment from the Database - */ - async deleteComment(slug: string, id: number) { - return await this.requests.delete(routes.recipesSlugCommentsId(slug, id)); - } - async parseIngredients(parser: Parser, ingredients: Array) { parser = parser || "nlp"; return await this.requests.post(routes.recipesParseIngredients, { parser, ingredients }); diff --git a/frontend/api/class-interfaces/recipes/types.ts b/frontend/api/class-interfaces/recipes/types.ts new file mode 100644 index 000000000..1dda8439f --- /dev/null +++ b/frontend/api/class-interfaces/recipes/types.ts @@ -0,0 +1,83 @@ +import { Category } from "../categories"; +import { Tag } from "../tags"; + +export type Parser = "nlp" | "brute"; + +export interface Confidence { + average?: number; + comment?: number; + name?: number; + unit?: number; + quantity?: number; + food?: number; +} + +export interface Unit { + name: string; + description: string; + fraction: boolean; + abbreviation: string; +} + +export interface Food { + name: string; + description?: string; +} + +export interface Ingredient { + referenceId: string; + title: string; + note: string; + unit: Unit | null; + food: Food | null; + disableAmount: boolean; + quantity: number; +} + +export interface ParsedIngredient { + confidence: Confidence; + ingredient: Ingredient; +} + +export interface BulkCreateRecipe { + url: string; + categories: Category[]; + tags: Tag[]; +} + +export interface BulkCreatePayload { + imports: BulkCreateRecipe[]; +} + +export interface RecipeZipToken { + token: string; +} + +export interface CreateAsset { + name: string; + icon: string; + extension: string; + file?: File; +} + +export interface RecipeCommentCreate { + recipeId: number; + text: string; +} + +export interface RecipeCommentUpdate extends RecipeCommentCreate { + id: string; +} + +interface RecipeCommentUser { + id: string; + username: string; + admin: boolean; +} + +export interface RecipeComment extends RecipeCommentUpdate { + createdAt: any; + updatedAt: any; + userId: number; + user: RecipeCommentUser; +} diff --git a/frontend/api/class-interfaces/tools.ts b/frontend/api/class-interfaces/tools.ts new file mode 100644 index 000000000..abc0e98a2 --- /dev/null +++ b/frontend/api/class-interfaces/tools.ts @@ -0,0 +1,22 @@ +import { BaseCRUDAPI } from "../_base"; + +const prefix = "/api"; + +export interface CreateTool { + name: string; + onHand: boolean; +} + +export interface Tool extends CreateTool { + id: number; +} + +const routes = { + tools: `${prefix}/tools`, + toolsId: (id: string) => `${prefix}/tools/${id}`, +}; + +export class ToolsApi extends BaseCRUDAPI { + baseRoute: string = routes.tools; + itemRoute = routes.toolsId; +} diff --git a/frontend/api/index.ts b/frontend/api/index.ts index eb00d8251..92a23a69a 100644 --- a/frontend/api/index.ts +++ b/frontend/api/index.ts @@ -18,6 +18,7 @@ import { EmailAPI } from "./class-interfaces/email"; import { BulkActionsAPI } from "./class-interfaces/recipe-bulk-actions"; import { GroupServerTaskAPI } from "./class-interfaces/group-tasks"; import { AdminAPI } from "./admin-api"; +import { ToolsApi } from "./class-interfaces/tools"; import { ApiRequestInstance } from "~/types/api"; class Api { @@ -40,7 +41,7 @@ class Api { public email: EmailAPI; public bulk: BulkActionsAPI; public grouperServerTasks: GroupServerTaskAPI; - + public tools: ToolsApi; // Utils public upload: UploadFile; @@ -55,6 +56,7 @@ class Api { this.tags = new TagsAPI(requests); this.units = new UnitAPI(requests); this.foods = new FoodAPI(requests); + this.tools = new ToolsApi(requests); // Users this.users = new UserApi(requests); diff --git a/frontend/components/Domain/Recipe/RecipeAssets.vue b/frontend/components/Domain/Recipe/RecipeAssets.vue index 995d1cb85..424964b64 100644 --- a/frontend/components/Domain/Recipe/RecipeAssets.vue +++ b/frontend/components/Domain/Recipe/RecipeAssets.vue @@ -23,10 +23,10 @@ {{ $globals.icons.download }}
- + {{ $globals.icons.delete }} - +
@@ -35,12 +35,10 @@
- - - diff --git a/frontend/components/Domain/Recipe/RecipeCategoryTagSelector.vue b/frontend/components/Domain/Recipe/RecipeCategoryTagSelector.vue index 58906d68d..73da7993f 100644 --- a/frontend/components/Domain/Recipe/RecipeCategoryTagSelector.vue +++ b/frontend/components/Domain/Recipe/RecipeCategoryTagSelector.vue @@ -43,7 +43,7 @@ - - \ No newline at end of file +}); + \ No newline at end of file diff --git a/frontend/components/Domain/Recipe/RecipeIngredients.vue b/frontend/components/Domain/Recipe/RecipeIngredients.vue index 8403a6436..c1764306b 100644 --- a/frontend/components/Domain/Recipe/RecipeIngredients.vue +++ b/frontend/components/Domain/Recipe/RecipeIngredients.vue @@ -1,7 +1,7 @@