mirror of
				https://github.com/mealie-recipes/mealie.git
				synced 2025-10-29 17:24:31 -04:00 
			
		
		
		
	refactor(frontend): 💄 Imrove UI for parser
This commit is contained in:
		| @@ -59,9 +59,6 @@ | |||||||
|             <RecipeIngredientFoodDialog class="mx-2" block small /> |             <RecipeIngredientFoodDialog class="mx-2" block small /> | ||||||
|           </template> |           </template> | ||||||
|         </v-autocomplete> |         </v-autocomplete> | ||||||
|         <template v-if="!checkForFood(value.food)"> |  | ||||||
|           '{{ value.food && value.food !== "" ? value.food.name : null }}' does not exists. Would you like to create it? |  | ||||||
|         </template> |  | ||||||
|       </v-col> |       </v-col> | ||||||
|       <v-col sm="12" md="" cols="12"> |       <v-col sm="12" md="" cols="12"> | ||||||
|         <v-text-field v-model="value.note" hide-details dense solo class="mx-1" placeholder="Notes"> |         <v-text-field v-model="value.note" hide-details dense solo class="mx-1" placeholder="Notes"> | ||||||
| @@ -95,7 +92,6 @@ import RecipeIngredientFoodDialog from "./RecipeIngredientFoodDialog.vue"; | |||||||
| import { useFoods } from "~/composables/use-recipe-foods"; | import { useFoods } from "~/composables/use-recipe-foods"; | ||||||
| import { useUnits } from "~/composables/use-recipe-units"; | import { useUnits } from "~/composables/use-recipe-units"; | ||||||
| import { validators } from "~/composables/use-validators"; | import { validators } from "~/composables/use-validators"; | ||||||
| import { RecipeIngredientFood } from "~/types/api-types/recipe"; |  | ||||||
|  |  | ||||||
| export default defineComponent({ | export default defineComponent({ | ||||||
|   components: { RecipeIngredientUnitDialog, RecipeIngredientFoodDialog }, |   components: { RecipeIngredientUnitDialog, RecipeIngredientFoodDialog }, | ||||||
| @@ -119,20 +115,6 @@ export default defineComponent({ | |||||||
|       showTitle: false, |       showTitle: false, | ||||||
|     }); |     }); | ||||||
|  |  | ||||||
|     function checkForUnit(unit: RecipeIngredientFood) { |  | ||||||
|       if (units.value && unit?.name) { |  | ||||||
|         return units.value.some((u) => u.name === unit.name); |  | ||||||
|       } |  | ||||||
|       return false; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     function checkForFood(food: RecipeIngredientFood) { |  | ||||||
|       if (foods.value && food?.name) { |  | ||||||
|         return foods.value.some((f) => f.name === food.name); |  | ||||||
|       } |  | ||||||
|       return false; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     function toggleTitle() { |     function toggleTitle() { | ||||||
|       if (value.title) { |       if (value.title) { | ||||||
|         state.showTitle = false; |         state.showTitle = false; | ||||||
| @@ -151,8 +133,6 @@ export default defineComponent({ | |||||||
|       units, |       units, | ||||||
|       ...toRefs(state), |       ...toRefs(state), | ||||||
|       toggleTitle, |       toggleTitle, | ||||||
|       checkForUnit, |  | ||||||
|       checkForFood, |  | ||||||
|     }; |     }; | ||||||
|   }, |   }, | ||||||
| }); | }); | ||||||
|   | |||||||
| @@ -10,7 +10,10 @@ | |||||||
|         </v-btn> |         </v-btn> | ||||||
|       </template> |       </template> | ||||||
|       <v-card width="400"> |       <v-card width="400"> | ||||||
|         <v-card-title class="mb-1 pb-0"> Warning Experimental </v-card-title> |         <v-card-title class="mb-1 pb-0"> | ||||||
|  |           <v-icon left color="warning"> {{ $globals.icons.alert }}</v-icon> Experimental | ||||||
|  |         </v-card-title> | ||||||
|  |         <v-divider class="mx-2"> </v-divider> | ||||||
|         <v-card-text> |         <v-card-text> | ||||||
|           Mealie can use natural language processing to attempt to parse and create units, and foods for your Recipe |           Mealie can use natural language processing to attempt to parse and create units, and foods for your Recipe | ||||||
|           ingredients. This is experimental and may not work as expected. If you choose to not use the parsed results |           ingredients. This is experimental and may not work as expected. If you choose to not use the parsed results | ||||||
| @@ -29,10 +32,32 @@ | |||||||
|     </v-menu> |     </v-menu> | ||||||
|     <BaseDialog ref="domParsedDataDialog" width="100%"> |     <BaseDialog ref="domParsedDataDialog" width="100%"> | ||||||
|       <v-card-text> |       <v-card-text> | ||||||
|         <div v-for="(ing, index) in parsedData.ingredient" :key="index"> |         <v-expansion-panels v-model="panels" multiple> | ||||||
|           <div class="ml-10 text-body-1" :class="index > 0 ? 'mt-4' : null">{{ ingredients[index].note }}</div> |           <v-expansion-panel v-for="(ing, index) in parsedData.ingredient" :key="index"> | ||||||
|           <RecipeIngredientEditor :value="ing" /> |             <v-expansion-panel-header class="my-0 py-0"> | ||||||
|  |               <div class="text-body-1"> | ||||||
|  |                 <span> | ||||||
|  |                   <v-icon v-if="errors[index].foodError" color="warning"> | ||||||
|  |                     {{ $globals.icons.close }} | ||||||
|  |                   </v-icon> | ||||||
|  |                   <v-icon v-else color="success"> | ||||||
|  |                     {{ $globals.icons.check }} | ||||||
|  |                   </v-icon> | ||||||
|  |                 </span> | ||||||
|  |                 {{ ingredients[index].note }} | ||||||
|               </div> |               </div> | ||||||
|  |             </v-expansion-panel-header> | ||||||
|  |             <v-expansion-panel-content class="pb-0 mb-0"> | ||||||
|  |               <RecipeIngredientEditor v-model="parsedData.ingredient[index]" /> | ||||||
|  |               <v-card-actions> | ||||||
|  |                 <v-spacer></v-spacer> | ||||||
|  |                 <BaseButton v-if="errors[index].foodError" color="warning" small @click="createFood(ing.food, index)"> | ||||||
|  |                   {{ errors[index].foodErrorMessage }} | ||||||
|  |                 </BaseButton> | ||||||
|  |               </v-card-actions> | ||||||
|  |             </v-expansion-panel-content> | ||||||
|  |           </v-expansion-panel> | ||||||
|  |         </v-expansion-panels> | ||||||
|       </v-card-text> |       </v-card-text> | ||||||
|     </BaseDialog> |     </BaseDialog> | ||||||
|   </div> |   </div> | ||||||
| @@ -42,7 +67,18 @@ | |||||||
| import { defineComponent, ref } from "@nuxtjs/composition-api"; | import { defineComponent, ref } from "@nuxtjs/composition-api"; | ||||||
| import RecipeIngredientEditor from "./RecipeIngredientEditor.vue"; | import RecipeIngredientEditor from "./RecipeIngredientEditor.vue"; | ||||||
| import { useApiSingleton } from "~/composables/use-api"; | import { useApiSingleton } from "~/composables/use-api"; | ||||||
| import { RecipeIngredient } from "~/types/api-types/recipe"; | import { RecipeIngredient, RecipeIngredientUnit } from "~/types/api-types/recipe"; | ||||||
|  | import { useFoods } from "~/composables/use-recipe-foods"; | ||||||
|  | import { useUnits } from "~/composables/use-recipe-units"; | ||||||
|  | import { Food } from "~/api/class-interfaces/recipe-foods"; | ||||||
|  |  | ||||||
|  | interface Error { | ||||||
|  |   ingredientIndex: number; | ||||||
|  |   unitError: Boolean; | ||||||
|  |   unitErrorMessage: string; | ||||||
|  |   foodError: Boolean; | ||||||
|  |   foodErrorMessage: string; | ||||||
|  | } | ||||||
|  |  | ||||||
| export default defineComponent({ | export default defineComponent({ | ||||||
|   components: { |   components: { | ||||||
| @@ -60,8 +96,36 @@ export default defineComponent({ | |||||||
|  |  | ||||||
|     const parsedData = ref<any>([]); |     const parsedData = ref<any>([]); | ||||||
|  |  | ||||||
|  |     const { foods, workingFoodData, actions } = useFoods(); | ||||||
|  |     const { units } = useUnits(); | ||||||
|  |  | ||||||
|     const domParsedDataDialog = ref(null); |     const domParsedDataDialog = ref(null); | ||||||
|  |  | ||||||
|  |     const panels = ref<number[]>([]); | ||||||
|  |     const errors = ref<Error[]>([]); | ||||||
|  |  | ||||||
|  |     function checkForUnit(unit: RecipeIngredientUnit) { | ||||||
|  |       if (units.value && unit?.name) { | ||||||
|  |         return units.value.some((u) => u.name === unit.name); | ||||||
|  |       } | ||||||
|  |       return false; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     function checkForFood(food: Food) { | ||||||
|  |       if (foods.value && food?.name) { | ||||||
|  |         return foods.value.some((f) => f.name === food.name); | ||||||
|  |       } | ||||||
|  |       return false; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     async function createFood(food: Food, index: number) { | ||||||
|  |       workingFoodData.name = food.name; | ||||||
|  |  | ||||||
|  |       parsedData.value[index] = await actions.createOne(); | ||||||
|  |  | ||||||
|  |       errors.value[index].foodError = false; | ||||||
|  |     } | ||||||
|  |  | ||||||
|     async function parseIngredients() { |     async function parseIngredients() { | ||||||
|       // @ts-ignore -> No idea what it's talking about |       // @ts-ignore -> No idea what it's talking about | ||||||
|       const ingredientNotes = ingredients.map((ing: RecipeIngredient) => ing.note); |       const ingredientNotes = ingredients.map((ing: RecipeIngredient) => ing.note); | ||||||
| @@ -73,12 +137,38 @@ export default defineComponent({ | |||||||
|         domParsedDataDialog.value.open(); |         domParsedDataDialog.value.open(); | ||||||
|         console.log(data); |         console.log(data); | ||||||
|         parsedData.value = data; |         parsedData.value = data; | ||||||
|  |  | ||||||
|  |         // @ts-ignore | ||||||
|  |         errors.value = data.ingredient.map((ing, index: number) => { | ||||||
|  |           const unitError = !checkForUnit(ing.unit); | ||||||
|  |           const foodError = !checkForFood(ing.food); | ||||||
|  |  | ||||||
|  |           let unitErrorMessage = ""; | ||||||
|  |           let foodErrorMessage = ""; | ||||||
|  |  | ||||||
|  |           if (unitError || foodError) { | ||||||
|  |             if (unitError) { | ||||||
|  |               unitErrorMessage = `Create missing unit '${ing.unit.name || "No unit"}'`; | ||||||
|             } |             } | ||||||
|  |  | ||||||
|       console.log("ingredientNotes", ingredientNotes); |             if (foodError) { | ||||||
|  |               panels.value.push(index); | ||||||
|  |               foodErrorMessage = `Create missing food '${ing.food.name || "No food"}'?`; | ||||||
|  |             } | ||||||
|           } |           } | ||||||
|  |  | ||||||
|     return { api, parseIngredients, parsedData, domParsedDataDialog }; |           return { | ||||||
|  |             ingredientIndex: index, | ||||||
|  |             unitError, | ||||||
|  |             unitErrorMessage, | ||||||
|  |             foodError, | ||||||
|  |             foodErrorMessage, | ||||||
|  |           }; | ||||||
|  |         }); | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     return { api, parseIngredients, parsedData, domParsedDataDialog, panels, errors, createFood }; | ||||||
|   }, |   }, | ||||||
| }); | }); | ||||||
| </script> | </script> | ||||||
|   | |||||||
| @@ -48,6 +48,7 @@ export const useFoods = function () { | |||||||
|       const { data } = await api.foods.createOne(workingFoodData); |       const { data } = await api.foods.createOne(workingFoodData); | ||||||
|       if (data && foodStore?.value) { |       if (data && foodStore?.value) { | ||||||
|         foodStore.value.push(data); |         foodStore.value.push(data); | ||||||
|  |         return data; | ||||||
|       } else { |       } else { | ||||||
|         this.refreshAll(); |         this.refreshAll(); | ||||||
|       } |       } | ||||||
|   | |||||||
| @@ -250,7 +250,7 @@ export default { | |||||||
|           secondary: "#973542", |           secondary: "#973542", | ||||||
|           success: "#43A047", |           success: "#43A047", | ||||||
|           info: "#1976d2", |           info: "#1976d2", | ||||||
|           warning: "#FF4081", |           warning: "#FF6D00", | ||||||
|           error: "#EF5350", |           error: "#EF5350", | ||||||
|         }, |         }, | ||||||
|         light: { |         light: { | ||||||
| @@ -259,7 +259,7 @@ export default { | |||||||
|           secondary: "#973542", |           secondary: "#973542", | ||||||
|           success: "#43A047", |           success: "#43A047", | ||||||
|           info: "#1976d2", |           info: "#1976d2", | ||||||
|           warning: "#FF4081", |           warning: "#FF6D00", | ||||||
|           error: "#EF5350", |           error: "#EF5350", | ||||||
|         }, |         }, | ||||||
|       }, |       }, | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user