1
0
Fork 0
mirror of https://github.com/mealie-recipes/mealie.git synced 2025-08-05 05:25:26 +02:00

feat: Migrate from Tandoor (#2438)

* added tandoor migration to backend

* added tandoor migration to frontend

* updated tests

* ignore 0 amounts

* refactored ingredient display calculation

* fix parsing tandoor recipes with optional data

* generated frontend types

* fixed inconsistent default handling and from_orm

* removed unused imports
This commit is contained in:
Michael Genson 2023-07-23 12:52:09 -05:00 committed by GitHub
parent c25b58e404
commit 0f896107f9
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
18 changed files with 559 additions and 236 deletions

View file

@ -11,6 +11,8 @@ function sanitizeIngredientHTML(rawHtml: string) {
}
export function parseIngredientText(ingredient: RecipeIngredient, disableAmount: boolean, scale = 1): string {
// TODO: the backend now supplies a "display" property which does this for us, so we don't need this function
if (disableAmount) {
return ingredient.note || "";
}

View file

@ -332,6 +332,10 @@
"description-long": "Mealie can import recipes from the Mealie application from a pre v1.0 release. Export your recipes from your old instance, and upload the zip file below. Note that only recipes can be imported from the export.",
"title": "Mealie Pre v1.0"
},
"tandoor": {
"description-long": "Mealie can import recipes from Tandoor. Export your data in the \"Default\" format, then upload the .zip below.",
"title": "Tandoor Recipes"
},
"recipe-data-migrations": "Recipe Data Migrations",
"recipe-data-migrations-explanation": "Recipes can be migrated from another supported application to Mealie. This is a great way to get started with Mealie.",
"choose-migration-type": "Choose Migration Type",
@ -341,8 +345,7 @@
"recipe-1": "Recipe 1",
"recipe-2": "Recipe 2",
"paprika-text": "Mealie can import recipes from the Paprika application. Export your recipes from paprika, rename the export extension to .zip and upload it below.",
"mealie-text": "Mealie can import recipes from the Mealie application from a pre v1.0 release. Export your recipes from your old instance, and upload the zip file below. Note that only recipes can be imported from the export.",
"previous-migrations": "Previous Migrations"
"mealie-text": "Mealie can import recipes from the Mealie application from a pre v1.0 release. Export your recipes from your old instance, and upload the zip file below. Note that only recipes can be imported from the export."
},
"new-recipe": {
"bulk-add": "Bulk Add",

View file

@ -6,7 +6,7 @@
*/
export type WebhookType = "mealplan";
export type SupportedMigrations = "nextcloud" | "chowdown" | "copymethat" | "paprika" | "mealie_alpha";
export type SupportedMigrations = "nextcloud" | "chowdown" | "copymethat" | "paprika" | "mealie_alpha" | "tandoor";
export interface CreateGroupPreferences {
privateGroup?: boolean;
@ -247,71 +247,43 @@ export interface SetPermissions {
}
export interface ShoppingListAddRecipeParams {
recipeIncrementQuantity?: number;
recipeIngredients?: RecipeIngredient[];
}
export interface ShoppingListCreate {
name?: string;
extras?: {
[k: string]: unknown;
};
createdAt?: string;
updateAt?: string;
}
export interface ShoppingListItemBase {
shoppingListId: string;
checked?: boolean;
position?: number;
isFood?: boolean;
note?: string;
export interface RecipeIngredient {
quantity?: number;
foodId?: string;
labelId?: string;
unitId?: string;
extras?: {
[k: string]: unknown;
};
}
export interface ShoppingListItemCreate {
shoppingListId: string;
checked?: boolean;
position?: number;
isFood?: boolean;
unit?: IngredientUnit | CreateIngredientUnit;
food?: IngredientFood | CreateIngredientFood;
note?: string;
quantity?: number;
foodId?: string;
labelId?: string;
unitId?: string;
extras?: {
[k: string]: unknown;
};
recipeReferences?: ShoppingListItemRecipeRefCreate[];
}
export interface ShoppingListItemRecipeRefCreate {
recipeId: string;
recipeQuantity?: number;
recipeScale?: number;
}
export interface ShoppingListItemOut {
shoppingListId: string;
checked?: boolean;
position?: number;
isFood?: boolean;
note?: string;
quantity?: number;
foodId?: string;
labelId?: string;
unitId?: string;
extras?: {
[k: string]: unknown;
};
id: string;
disableAmount?: boolean;
display?: string;
food?: IngredientFood;
label?: MultiPurposeLabelSummary;
unit?: IngredientUnit;
recipeReferences?: ShoppingListItemRecipeRefOut[];
title?: string;
originalText?: string;
referenceId?: string;
}
export interface IngredientUnit {
name: string;
description?: string;
extras?: {
[k: string]: unknown;
};
fraction?: boolean;
abbreviation?: string;
useAbbreviation?: boolean;
id: string;
createdAt?: string;
updateAt?: string;
}
export interface CreateIngredientUnit {
name: string;
description?: string;
extras?: {
[k: string]: unknown;
};
fraction?: boolean;
abbreviation?: string;
useAbbreviation?: boolean;
}
export interface IngredientFood {
name: string;
description?: string;
@ -330,16 +302,84 @@ export interface MultiPurposeLabelSummary {
groupId: string;
id: string;
}
export interface IngredientUnit {
export interface CreateIngredientFood {
name: string;
description?: string;
extras?: {
[k: string]: unknown;
};
fraction?: boolean;
abbreviation?: string;
useAbbreviation?: boolean;
labelId?: string;
}
export interface ShoppingListCreate {
name?: string;
extras?: {
[k: string]: unknown;
};
createdAt?: string;
updateAt?: string;
}
export interface ShoppingListItemBase {
quantity?: number;
unit?: IngredientUnit | CreateIngredientUnit;
food?: IngredientFood | CreateIngredientFood;
note?: string;
isFood?: boolean;
disableAmount?: boolean;
display?: string;
shoppingListId: string;
checked?: boolean;
position?: number;
foodId?: string;
labelId?: string;
unitId?: string;
extras?: {
[k: string]: unknown;
};
}
export interface ShoppingListItemCreate {
quantity?: number;
unit?: IngredientUnit | CreateIngredientUnit;
food?: IngredientFood | CreateIngredientFood;
note?: string;
isFood?: boolean;
disableAmount?: boolean;
display?: string;
shoppingListId: string;
checked?: boolean;
position?: number;
foodId?: string;
labelId?: string;
unitId?: string;
extras?: {
[k: string]: unknown;
};
recipeReferences?: ShoppingListItemRecipeRefCreate[];
}
export interface ShoppingListItemRecipeRefCreate {
recipeId: string;
recipeQuantity?: number;
recipeScale?: number;
}
export interface ShoppingListItemOut {
quantity?: number;
unit?: IngredientUnit;
food?: IngredientFood;
note?: string;
isFood?: boolean;
disableAmount?: boolean;
display?: string;
shoppingListId: string;
checked?: boolean;
position?: number;
foodId?: string;
labelId?: string;
unitId?: string;
extras?: {
[k: string]: unknown;
};
id: string;
label?: MultiPurposeLabelSummary;
recipeReferences?: ShoppingListItemRecipeRefOut[];
createdAt?: string;
updateAt?: string;
}
@ -358,12 +398,16 @@ export interface ShoppingListItemRecipeRefUpdate {
shoppingListItemId: string;
}
export interface ShoppingListItemUpdate {
quantity?: number;
unit?: IngredientUnit | CreateIngredientUnit;
food?: IngredientFood | CreateIngredientFood;
note?: string;
isFood?: boolean;
disableAmount?: boolean;
display?: string;
shoppingListId: string;
checked?: boolean;
position?: number;
isFood?: boolean;
note?: string;
quantity?: number;
foodId?: string;
labelId?: string;
unitId?: string;
@ -376,12 +420,16 @@ export interface ShoppingListItemUpdate {
* Only used for bulk update operations where the shopping list item id isn't already supplied
*/
export interface ShoppingListItemUpdateBulk {
quantity?: number;
unit?: IngredientUnit | CreateIngredientUnit;
food?: IngredientFood | CreateIngredientFood;
note?: string;
isFood?: boolean;
disableAmount?: boolean;
display?: string;
shoppingListId: string;
checked?: boolean;
position?: number;
isFood?: boolean;
note?: string;
quantity?: number;
foodId?: string;
labelId?: string;
unitId?: string;
@ -512,3 +560,12 @@ export interface ShoppingListUpdate {
id: string;
listItems?: ShoppingListItemOut[];
}
export interface RecipeIngredientBase {
quantity?: number;
unit?: IngredientUnit | CreateIngredientUnit;
food?: IngredientFood | CreateIngredientFood;
note?: string;
isFood?: boolean;
disableAmount?: boolean;
display?: string;
}

View file

@ -178,12 +178,14 @@ export interface ParsedIngredient {
ingredient: RecipeIngredient;
}
export interface RecipeIngredient {
title?: string;
note?: string;
quantity?: number;
unit?: IngredientUnit | CreateIngredientUnit;
food?: IngredientFood | CreateIngredientFood;
note?: string;
isFood?: boolean;
disableAmount?: boolean;
quantity?: number;
display?: string;
title?: string;
originalText?: string;
referenceId?: string;
}
@ -303,6 +305,15 @@ export interface RecipeCommentUpdate {
export interface RecipeDuplicate {
name?: string;
}
export interface RecipeIngredientBase {
quantity?: number;
unit?: IngredientUnit | CreateIngredientUnit;
food?: IngredientFood | CreateIngredientFood;
note?: string;
isFood?: boolean;
disableAmount?: boolean;
display?: string;
}
export interface RecipeLastMade {
timestamp: string;
}

View file

@ -80,6 +80,7 @@ const MIGRATIONS = {
copymethat: "copymethat",
paprika: "paprika",
mealie: "mealie_alpha",
tandoor: "tandoor",
};
export default defineComponent({
@ -118,6 +119,10 @@ export default defineComponent({
text: i18n.tc("migration.mealie-pre-v1.title"),
value: MIGRATIONS.mealie,
},
{
text: i18n.tc("migration.tandoor.title"),
value: MIGRATIONS.tandoor,
},
];
const _content = {
@ -267,6 +272,45 @@ export default defineComponent({
},
],
},
[MIGRATIONS.tandoor]: {
text: i18n.tc("migration.tandoor.description-long"),
tree: [
{
id: 1,
icon: $globals.icons.zip,
name: "tandoor_default_export_full_2023-06-29.zip",
children: [
{
id: 2,
name: "1.zip",
icon: $globals.icons.zip,
children: [
{ id: 3, name: "image.jpeg", icon: $globals.icons.fileImage },
{ id: 4, name: "recipe.json", icon: $globals.icons.codeJson },
]
},
{
id: 5,
name: "2.zip",
icon: $globals.icons.zip,
children: [
{ id: 6, name: "image.jpeg", icon: $globals.icons.fileImage },
{ id: 7, name: "recipe.json", icon: $globals.icons.codeJson },
]
},
{
id: 8,
name: "3.zip",
icon: $globals.icons.zip,
children: [
{ id: 9, name: "image.jpeg", icon: $globals.icons.fileImage },
{ id: 10, name: "recipe.json", icon: $globals.icons.codeJson },
]
}
]
}
],
},
};
function setFileObject(fileObject: File) {