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:
parent
c25b58e404
commit
0f896107f9
18 changed files with 559 additions and 236 deletions
|
@ -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 || "";
|
||||
}
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue