From d34f39a9e0c6bd251598a193bfc9a584c3e95d05 Mon Sep 17 00:00:00 2001 From: vabene1111 Date: Wed, 19 Mar 2025 19:42:05 +0100 Subject: [PATCH] very basic app import working --- vue3/src/composables/useFileApi.ts | 32 +++++++++- vue3/src/pages/RecipeImportPage.vue | 93 +++++++++++++++++++++++------ vue3/src/utils/integration_utils.ts | 35 +++++++++++ 3 files changed, 139 insertions(+), 21 deletions(-) create mode 100644 vue3/src/utils/integration_utils.ts diff --git a/vue3/src/composables/useFileApi.ts b/vue3/src/composables/useFileApi.ts index a05aab500..92ce8fea5 100644 --- a/vue3/src/composables/useFileApi.ts +++ b/vue3/src/composables/useFileApi.ts @@ -54,7 +54,7 @@ export function useFileApi() { * @param file file object to upload or null to delete image (if no imageUrl is given) * @param imageUrl url of an image to download by server */ - function updateRecipeImage(recipeId: number, file: File|null, imageUrl?: string){ + function updateRecipeImage(recipeId: number, file: File | null, imageUrl?: string) { let formData = new FormData() if (file != null) { formData.append('image', file) @@ -80,7 +80,7 @@ export function useFileApi() { * uploads the given file to the image recognition endpoint * @param file file object to upload */ - function convertImageToRecipe(file: File){ + function convertImageToRecipe(file: File) { let formData = new FormData() if (file != null) { formData.append('image', file) @@ -99,5 +99,31 @@ export function useFileApi() { }) } - return {fileApiLoading, createOrUpdateUserFile, updateRecipeImage, convertImageToRecipe} + /** + * uploads the given files to the app import endpoint + * @param file array to import + * @param app app to import + * @param includeDuplicates if recipes that were found as duplicates should be imported as well + */ + function doAppImport(file: File, app: string, includeDuplicates: boolean) { + let formData = new FormData() + formData.append('type', app); + formData.append('duplicates', includeDuplicates ? 'true' : 'false') + // files.forEach(file => { + // formData.append('files', file) + // }) +formData.append('files', file) + + return fetch(getDjangoUrl(`api/import/`), { + method: 'POST', + headers: {'X-CSRFToken': getCookie('csrftoken')}, + body: formData + }).then(r => { + console.log(r) + }).finally(() => { + fileApiLoading.value = false + }) + } + + return {fileApiLoading, createOrUpdateUserFile, updateRecipeImage, convertImageToRecipe, doAppImport} } \ No newline at end of file diff --git a/vue3/src/pages/RecipeImportPage.vue b/vue3/src/pages/RecipeImportPage.vue index 91a326654..7ee7bf0ef 100644 --- a/vue3/src/pages/RecipeImportPage.vue +++ b/vue3/src/pages/RecipeImportPage.vue @@ -25,6 +25,13 @@ + @@ -82,11 +89,15 @@ - + + + + @@ -120,7 +131,6 @@ - @@ -292,22 +302,60 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - + @@ -333,19 +381,22 @@ import {useFileApi} from "@/composables/useFileApi"; import ModelSelect from "@/components/inputs/ModelSelect.vue"; import {useDisplay} from "vuetify"; import {useUrlSearchParams} from "@vueuse/core"; +import {INTEGRATIONS} from "@/utils/integration_utils"; +import {VFileUpload} from 'vuetify/labs/VFileUpload' const params = useUrlSearchParams('history', {}) const {mobile} = useDisplay() const router = useRouter() -const {updateRecipeImage, convertImageToRecipe, fileApiLoading} = useFileApi() +const {updateRecipeImage, convertImageToRecipe, doAppImport, fileApiLoading} = useFileApi() const importType = ref<'url' | 'ai' | 'app' | 'bookmarklet' | 'source'>("url") +const importApp = ref('DEFAULT') const stepper = ref("type") const dialog = ref(false) const loading = ref(false) const importUrl = ref("") - +const appImportFile = ref(null) const image = ref(null) const importResponse = ref({} as RecipeFromSourceResponse) @@ -399,6 +450,12 @@ function uploadAndConvertImage() { } } +function appImport() { + doAppImport(appImportFile.value, importApp.value, true).then(r => { + stepper.value = 'import_log' + }) +} + /** * create recipe in database */ diff --git a/vue3/src/utils/integration_utils.ts b/vue3/src/utils/integration_utils.ts new file mode 100644 index 000000000..d0a28e083 --- /dev/null +++ b/vue3/src/utils/integration_utils.ts @@ -0,0 +1,35 @@ + + +export type Integration = { + id: string, + name: string, + import: boolean, + export: boolean, + helpUrl: string, + imgSrc?: string, +} + +export const INTEGRATIONS: Array = [ + {id: 'DEFAULT', name: "Tandoor", import: true, export: true, helpUrl: 'https://docs.tandoor.dev/features/import_export/#default', imgSrc: 'https://raw.githubusercontent.com/TandoorRecipes/recipes/develop/docs/logo_color.svg'}, + {id: 'CHEFTAP', name: "Cheftap", import: true, export: false, helpUrl: 'https://docs.tandoor.dev/features/import_export/#cheftap'}, + {id: 'CHOWDOWN', name: "Chowdown", import: true, export: false, helpUrl: 'https://docs.tandoor.dev/features/import_export/#chowdown'}, + {id: 'COOKBOOKAPP', name: "CookBookApp", import: true, export: false, helpUrl: 'https://docs.tandoor.dev/features/import_export/#cookbookapp'}, + {id: 'COOKMATE', name: "Cookmate", import: true, export: false, helpUrl: 'https://docs.tandoor.dev/features/import_export/#cookmate'}, + {id: 'COPYMETHAT', name: "CopyMeThat", import: true, export: false, helpUrl: 'https://docs.tandoor.dev/features/import_export/#copymethat'}, + {id: 'DOMESTICA', name: "Domestica", import: true, export: false, helpUrl: 'https://docs.tandoor.dev/features/import_export/#domestica'}, + {id: 'MEALIE', name: "Mealie", import: true, export: false, helpUrl: 'https://docs.tandoor.dev/features/import_export/#mealie'}, + {id: 'MEALMASTER', name: "Mealmaster", import: true, export: false, helpUrl: 'https://docs.tandoor.dev/features/import_export/#mealmaster'}, + {id: 'MELARECIPES', name: "Melarecipes", import: true, export: false, helpUrl: 'https://docs.tandoor.dev/features/import_export/#melarecipes'}, + {id: 'NEXTCLOUD', name: "Nextcloud Cookbook", import: true, export: false, helpUrl: 'https://docs.tandoor.dev/features/import_export/#nextcloud'}, + {id: 'OPENEATS', name: "Openeats", import: true, export: false, helpUrl: 'https://docs.tandoor.dev/features/import_export/#openeats'}, + {id: 'PAPRIKA', name: "Paprika", import: true, export: false, helpUrl: 'https://docs.tandoor.dev/features/import_export/#paprika'}, + {id: 'PEPPERPLATE', name: "Pepperplate", import: true, export: false, helpUrl: 'https://docs.tandoor.dev/features/import_export/#pepperplate'}, + {id: 'PLANTOEAT', name: "Plantoeat", import: true, export: false, helpUrl: 'https://docs.tandoor.dev/features/import_export/#plantoeat'}, + {id: 'RECETTETEK', name: "RecetteTek", import: true, export: false, helpUrl: 'https://docs.tandoor.dev/features/import_export/#recettetek'}, + {id: 'RECIPEKEEPER', name: "Recipekeeper", import: true, export: false, helpUrl: 'https://docs.tandoor.dev/features/import_export/#recipekeeper'}, + {id: 'RECIPESAGE', name: "Recipesage", import: true, export: true, helpUrl: 'https://docs.tandoor.dev/features/import_export/#recipesage'}, + {id: 'REZKONV', name: "Rezkonv", import: true, export: false, helpUrl: 'https://docs.tandoor.dev/features/import_export/#rezkonv'}, + {id: 'SAFRON', name: "Safron", import: true, export: true, helpUrl: 'https://docs.tandoor.dev/features/import_export/#safron'}, + {id: 'REZEPTSUITEDE', name: "Rezeptsuite.de", import: true, export: false, helpUrl: 'https://docs.tandoor.dev/features/import_export/#rezeptsuitede'}, + {id: 'GOURMET', name: "Gourmet", import: true, export: false, helpUrl: 'https://docs.tandoor.dev/features/import_export/#gourmet'}, +]