mirror of
				https://github.com/mealie-recipes/mealie.git
				synced 2025-10-30 17:53:31 -04:00 
			
		
		
		
	Fix/multiple bug reports (#1002)
* fix type issues for #999 * fix regression #995 * remove error from frontend and log error #996 * cleanup darkmode on login page * keep primary color bg
This commit is contained in:
		| @@ -39,26 +39,29 @@ | |||||||
|         <span> Locked by Owner </span> |         <span> Locked by Owner </span> | ||||||
|       </v-tooltip> |       </v-tooltip> | ||||||
|  |  | ||||||
|       <RecipeContextMenu |       <ClientOnly> | ||||||
|         show-print |         <RecipeContextMenu | ||||||
|         :menu-top="false" |           show-print | ||||||
|         :slug="slug" |           :menu-top="false" | ||||||
|         :menu-icon="$globals.icons.mdiDotsHorizontal" |           :name="name" | ||||||
|         fab |           :slug="slug" | ||||||
|         color="info" |           :menu-icon="$globals.icons.mdiDotsHorizontal" | ||||||
|         :card-menu="false" |           fab | ||||||
|         :recipe-id="recipeId" |           color="info" | ||||||
|         :use-items="{ |           :card-menu="false" | ||||||
|           delete: false, |           :recipe-id="recipeId" | ||||||
|           edit: false, |           :use-items="{ | ||||||
|           download: true, |             delete: false, | ||||||
|           mealplanner: true, |             edit: false, | ||||||
|           shoppingList: true, |             download: true, | ||||||
|           print: true, |             mealplanner: true, | ||||||
|           share: true, |             shoppingList: true, | ||||||
|         }" |             print: true, | ||||||
|         @print="$emit('print')" |             share: true, | ||||||
|       /> |           }" | ||||||
|  |           @print="$emit('print')" | ||||||
|  |         /> | ||||||
|  |       </ClientOnly> | ||||||
|     </div> |     </div> | ||||||
|     <div v-if="value" class="custom-btn-group mb-"> |     <div v-if="value" class="custom-btn-group mb-"> | ||||||
|       <v-btn |       <v-btn | ||||||
|   | |||||||
| @@ -23,7 +23,7 @@ | |||||||
| <script lang="ts"> | <script lang="ts"> | ||||||
| import { computed, defineComponent, useContext } from "@nuxtjs/composition-api"; | import { computed, defineComponent, useContext } from "@nuxtjs/composition-api"; | ||||||
| import { useUserApi } from "~/composables/api"; | import { useUserApi } from "~/composables/api"; | ||||||
| import {UserOut} from "~/types/api-types/user"; | import { UserOut } from "~/types/api-types/user"; | ||||||
| export default defineComponent({ | export default defineComponent({ | ||||||
|   props: { |   props: { | ||||||
|     slug: { |     slug: { | ||||||
| @@ -49,19 +49,15 @@ export default defineComponent({ | |||||||
|     const isFavorite = computed(() => user.value?.favoriteRecipes?.includes(props.slug)); |     const isFavorite = computed(() => user.value?.favoriteRecipes?.includes(props.slug)); | ||||||
|  |  | ||||||
|     async function toggleFavorite() { |     async function toggleFavorite() { | ||||||
|       console.log("Favorited?"); |  | ||||||
|       if (!isFavorite.value) { |       if (!isFavorite.value) { | ||||||
|         await api.users.addFavorite(user.value?.id, props.slug); |         await api.users.addFavorite(user.value?.id, props.slug); | ||||||
|       } else { |       } else { | ||||||
|         await api.users.removeFavorite(user.value?.id, props.slug); |         await api.users.removeFavorite(user.value?.id, props.slug); | ||||||
|       } |       } | ||||||
|       $auth.fetchUser(); |       $auth.fetchUser(); | ||||||
|     }; |     } | ||||||
|  |  | ||||||
|     return { isFavorite, toggleFavorite }; |     return { isFavorite, toggleFavorite }; | ||||||
|   }, |   }, | ||||||
| }); | }); | ||||||
| </script> | </script> | ||||||
|  |  | ||||||
| <style lang="scss" scoped> |  | ||||||
| </style> |  | ||||||
|   | |||||||
| @@ -1,4 +1,18 @@ | |||||||
| import { IncomingMessage } from "connect"; | import { IncomingMessage } from "connect"; | ||||||
|  | import { useDark } from "@vueuse/core"; | ||||||
|  | import { useContext } from "@nuxtjs/composition-api"; | ||||||
|  |  | ||||||
|  | export const useToggleDarkMode = () => { | ||||||
|  |   const isDark = useDark(); | ||||||
|  |   const { $vuetify } = useContext(); | ||||||
|  |  | ||||||
|  |   function toggleDark() { | ||||||
|  |     isDark.value = !$vuetify.theme.dark; | ||||||
|  |     $vuetify.theme.dark = !$vuetify.theme.dark; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   return toggleDark; | ||||||
|  | }; | ||||||
|  |  | ||||||
| export const useAsyncKey = function () { | export const useAsyncKey = function () { | ||||||
|   return String(Date.now()); |   return String(Date.now()); | ||||||
|   | |||||||
| @@ -62,11 +62,11 @@ | |||||||
|  |  | ||||||
| <script lang="ts"> | <script lang="ts"> | ||||||
| import { computed, defineComponent, onMounted, ref, useContext } from "@nuxtjs/composition-api"; | import { computed, defineComponent, onMounted, ref, useContext } from "@nuxtjs/composition-api"; | ||||||
| import { useDark } from "@vueuse/core"; |  | ||||||
| import AppHeader from "@/components/Layout/AppHeader.vue"; | import AppHeader from "@/components/Layout/AppHeader.vue"; | ||||||
| import AppSidebar from "@/components/Layout/AppSidebar.vue"; | import AppSidebar from "@/components/Layout/AppSidebar.vue"; | ||||||
| import TheSnackbar from "@/components/Layout/TheSnackbar.vue"; | import TheSnackbar from "@/components/Layout/TheSnackbar.vue"; | ||||||
| import { useCookbooks } from "~/composables/use-group-cookbooks"; | import { useCookbooks } from "~/composables/use-group-cookbooks"; | ||||||
|  | import { useToggleDarkMode } from "~/composables/use-utils"; | ||||||
|  |  | ||||||
| export default defineComponent({ | export default defineComponent({ | ||||||
|   components: { AppHeader, AppSidebar, TheSnackbar }, |   components: { AppHeader, AppSidebar, TheSnackbar }, | ||||||
| @@ -77,13 +77,7 @@ export default defineComponent({ | |||||||
|  |  | ||||||
|     const isAdmin = computed(() => $auth.user?.admin); |     const isAdmin = computed(() => $auth.user?.admin); | ||||||
|  |  | ||||||
|     const isDark = useDark(); |     const toggleDark = useToggleDarkMode(); | ||||||
|  |  | ||||||
|     function toggleDark() { |  | ||||||
|       isDark.value = !$vuetify.theme.dark; |  | ||||||
|       $vuetify.theme.dark = !$vuetify.theme.dark; |  | ||||||
|       console.log("toggleDark"); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     const sidebar = ref<boolean | null>(null); |     const sidebar = ref<boolean | null>(null); | ||||||
|  |  | ||||||
|   | |||||||
| @@ -45,10 +45,19 @@ | |||||||
|             {{ $t("general.test") }} |             {{ $t("general.test") }} | ||||||
|           </BaseButton> |           </BaseButton> | ||||||
|           <template v-if="tested"> |           <template v-if="tested"> | ||||||
|             <v-divider class="my-x"></v-divider> |             <v-divider class="my-x mt-6"></v-divider> | ||||||
|             <v-card-text> |             <v-card-text class="px-0"> | ||||||
|               Email Test Result: {{ success ? "Succeeded" : "Failed" }} |               <h4>Email Test Results</h4> | ||||||
|               <div>Errors: {{ error }}</div> |               <span class="pl-4"> | ||||||
|  |                 {{ success ? "Succeeded" : "Failed" }} | ||||||
|  |               </span> | ||||||
|  |  | ||||||
|  |               <!-- <template v-if="errors"> | ||||||
|  |                 <h4>Errors:</h4> | ||||||
|  |                 <span class="pl-4"> | ||||||
|  |                   {{ errors }} | ||||||
|  |                 </span> | ||||||
|  |               </template> --> | ||||||
|             </v-card-text> |             </v-card-text> | ||||||
|           </template> |           </template> | ||||||
|         </div> |         </div> | ||||||
| @@ -296,5 +305,4 @@ export default defineComponent({ | |||||||
| }); | }); | ||||||
| </script> | </script> | ||||||
|  |  | ||||||
| <style scoped> | <style scoped></style> | ||||||
| </style> |  | ||||||
|   | |||||||
| @@ -1,5 +1,12 @@ | |||||||
| <template> | <template> | ||||||
|   <v-container fill-height fluid class="d-flex justify-center align-center" style="background: #f5f8fa"> |   <v-container | ||||||
|  |     fill-height | ||||||
|  |     fluid | ||||||
|  |     class="d-flex justify-center align-center" | ||||||
|  |     :class="{ | ||||||
|  |       'bg-off-white': !$vuetify.theme.dark, | ||||||
|  |     }" | ||||||
|  |   > | ||||||
|     <v-card tag="section" class="d-flex flex-column align-center" width="600px"> |     <v-card tag="section" class="d-flex flex-column align-center" width="600px"> | ||||||
|       <v-toolbar width="100%" color="primary" class="d-flex justify-center mb-4" dark> |       <v-toolbar width="100%" color="primary" class="d-flex justify-center mb-4" dark> | ||||||
|         <v-toolbar-title class="headline text-h4"> Mealie </v-toolbar-title> |         <v-toolbar-title class="headline text-h4"> Mealie </v-toolbar-title> | ||||||
| @@ -7,14 +14,12 @@ | |||||||
|  |  | ||||||
|       <div class="icon-container"> |       <div class="icon-container"> | ||||||
|         <v-divider class="icon-divider"></v-divider> |         <v-divider class="icon-divider"></v-divider> | ||||||
|         <v-avatar size="102" color="grey lighten-2"> |         <v-avatar class="pa-2 icon-avatar" color="primary" size="100"> | ||||||
|           <v-avatar class="pa-2 icon-avatar" color="white" size="100"> |           <svg class="icon-white" style="width: 100px; height: 100px" viewBox="0 0 24 24"> | ||||||
|             <svg class="icon-primary" style="width: 100px; height: 100px" viewBox="0 0 24 24"> |             <path | ||||||
|               <path |               d="M8.1,13.34L3.91,9.16C2.35,7.59 2.35,5.06 3.91,3.5L10.93,10.5L8.1,13.34M13.41,13L20.29,19.88L18.88,21.29L12,14.41L5.12,21.29L3.71,19.88L13.36,10.22L13.16,10C12.38,9.23 12.38,7.97 13.16,7.19L17.5,2.82L18.43,3.74L15.19,7L16.15,7.94L19.39,4.69L20.31,5.61L17.06,8.85L18,9.81L21.26,6.56L22.18,7.5L17.81,11.84C17.03,12.62 15.77,12.62 15,11.84L14.78,11.64L13.41,13Z" | ||||||
|                 d="M8.1,13.34L3.91,9.16C2.35,7.59 2.35,5.06 3.91,3.5L10.93,10.5L8.1,13.34M13.41,13L20.29,19.88L18.88,21.29L12,14.41L5.12,21.29L3.71,19.88L13.36,10.22L13.16,10C12.38,9.23 12.38,7.97 13.16,7.19L17.5,2.82L18.43,3.74L15.19,7L16.15,7.94L19.39,4.69L20.31,5.61L17.06,8.85L18,9.81L21.26,6.56L22.18,7.5L17.81,11.84C17.03,12.62 15.77,12.62 15,11.84L14.78,11.64L13.41,13Z" |             /> | ||||||
|               /> |           </svg> | ||||||
|             </svg> |  | ||||||
|           </v-avatar> |  | ||||||
|         </v-avatar> |         </v-avatar> | ||||||
|       </div> |       </div> | ||||||
|  |  | ||||||
| @@ -91,16 +96,26 @@ | |||||||
|         </div> |         </div> | ||||||
|       </v-card-text> |       </v-card-text> | ||||||
|     </v-card> |     </v-card> | ||||||
|  |  | ||||||
|  |     <v-btn absolute bottom center @click="toggleDark"> | ||||||
|  |       <v-icon left> | ||||||
|  |         {{ $vuetify.theme.dark ? $globals.icons.weatherSunny : $globals.icons.weatherNight }} | ||||||
|  |       </v-icon> | ||||||
|  |       {{ $vuetify.theme.dark ? "Light Mode" : "Dark Mode" }} | ||||||
|  |     </v-btn> | ||||||
|   </v-container> |   </v-container> | ||||||
| </template> | </template> | ||||||
|  |  | ||||||
| <script lang="ts"> | <script lang="ts"> | ||||||
| import { defineComponent, ref, useContext, computed, reactive } from "@nuxtjs/composition-api"; | import { defineComponent, ref, useContext, computed, reactive } from "@nuxtjs/composition-api"; | ||||||
| import { alert } from "~/composables/use-toast"; | import { alert } from "~/composables/use-toast"; | ||||||
|  | import { useToggleDarkMode } from "~/composables/use-utils"; | ||||||
| export default defineComponent({ | export default defineComponent({ | ||||||
|   layout: "blank", |   layout: "blank", | ||||||
|  |  | ||||||
|   setup() { |   setup() { | ||||||
|  |     const toggleDark = useToggleDarkMode(); | ||||||
|  |  | ||||||
|     const { $auth } = useContext(); |     const { $auth } = useContext(); | ||||||
|     const context = useContext(); |     const context = useContext(); | ||||||
|  |  | ||||||
| @@ -147,6 +162,7 @@ export default defineComponent({ | |||||||
|       loggingIn, |       loggingIn, | ||||||
|       allowSignup, |       allowSignup, | ||||||
|       authenticate, |       authenticate, | ||||||
|  |       toggleDark, | ||||||
|     }; |     }; | ||||||
|   }, |   }, | ||||||
|  |  | ||||||
| @@ -167,6 +183,10 @@ export default defineComponent({ | |||||||
|   fill: var(--v-primary-base); |   fill: var(--v-primary-base); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | .icon-white { | ||||||
|  |   fill: white; | ||||||
|  | } | ||||||
|  |  | ||||||
| .icon-container { | .icon-container { | ||||||
|   display: flex; |   display: flex; | ||||||
|   flex-direction: column; |   flex-direction: column; | ||||||
| @@ -185,4 +205,8 @@ export default defineComponent({ | |||||||
|   border-color: rgba(0, 0, 0, 0.12); |   border-color: rgba(0, 0, 0, 0.12); | ||||||
|   border: 2px; |   border: 2px; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | .bg-off-white { | ||||||
|  |   background: #f5f8fa; | ||||||
|  | } | ||||||
| </style> | </style> | ||||||
|   | |||||||
| @@ -504,10 +504,12 @@ export default defineComponent({ | |||||||
|   async beforeRouteLeave(_to, _from, next) { |   async beforeRouteLeave(_to, _from, next) { | ||||||
|     const isSame = JSON.stringify(this.recipe) === JSON.stringify(this.originalRecipe); |     const isSame = JSON.stringify(this.recipe) === JSON.stringify(this.originalRecipe); | ||||||
|  |  | ||||||
|     console.log({ working: this.recipe, saved: this.originalRecipe }); |  | ||||||
|  |  | ||||||
|     if (this.form && !isSame && this.recipe?.slug !== undefined) { |     if (this.form && !isSame && this.recipe?.slug !== undefined) { | ||||||
|       if (window.confirm("You have unsaved changes. Do you want to save before leaving?")) { |       if ( | ||||||
|  |         window.confirm( | ||||||
|  |           "You have unsaved changes. Do you want to save before leaving?\n\nOkay to save, Cancel to discard changes." | ||||||
|  |         ) | ||||||
|  |       ) { | ||||||
|         await this.api.recipes.updateOne(this.recipe.slug, this.recipe); |         await this.api.recipes.updateOne(this.recipe.slug, this.recipe); | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
| @@ -558,7 +560,6 @@ export default defineComponent({ | |||||||
|  |  | ||||||
|     invoke(async () => { |     invoke(async () => { | ||||||
|       await until(recipe).not.toBeNull(); |       await until(recipe).not.toBeNull(); | ||||||
|  |  | ||||||
|       originalRecipe.value = deepCopy(recipe.value); |       originalRecipe.value = deepCopy(recipe.value); | ||||||
|     }); |     }); | ||||||
|  |  | ||||||
| @@ -746,6 +747,7 @@ export default defineComponent({ | |||||||
|     useMeta(metaData); |     useMeta(metaData); | ||||||
|  |  | ||||||
|     return { |     return { | ||||||
|  |       originalRecipe, | ||||||
|       createApiExtra, |       createApiExtra, | ||||||
|       apiNewKey, |       apiNewKey, | ||||||
|       enableLandscape, |       enableLandscape, | ||||||
|   | |||||||
| @@ -1,10 +1,10 @@ | |||||||
| import { Plugin } from "@nuxt/types" | import { Plugin } from "@nuxt/types"; | ||||||
| import { NuxtAxiosInstance } from "@nuxtjs/axios"; | import { NuxtAxiosInstance } from "@nuxtjs/axios"; | ||||||
| import { alert } from "~/composables/use-toast"; | import { alert } from "~/composables/use-toast"; | ||||||
|  |  | ||||||
| const toastPlugin: Plugin = ({ $axios }: { $axios: NuxtAxiosInstance }) => { | const toastPlugin: Plugin = ({ $axios }: { $axios: NuxtAxiosInstance }) => { | ||||||
|   $axios.onResponse((response) => { |   $axios.onResponse((response) => { | ||||||
|     if (response.data.message) { |     if (response?.data?.message) { | ||||||
|       alert.info(response.data.message); |       alert.info(response.data.message); | ||||||
|     } |     } | ||||||
|   }); |   }); | ||||||
| @@ -13,6 +13,6 @@ const toastPlugin: Plugin = ({ $axios }: { $axios: NuxtAxiosInstance }) => { | |||||||
|       alert.error(error.response.data.detail.message); |       alert.error(error.response.data.detail.message); | ||||||
|     } |     } | ||||||
|   }); |   }); | ||||||
| } | }; | ||||||
|  |  | ||||||
| export default toastPlugin; | export default toastPlugin; | ||||||
|   | |||||||
| @@ -1,6 +1,7 @@ | |||||||
| from abc import ABC, abstractmethod | from abc import ABC, abstractmethod | ||||||
|  |  | ||||||
| import emails | import emails | ||||||
|  | from emails.backend.response import SMTPResponse | ||||||
|  |  | ||||||
| from mealie.core.root_logger import get_logger | from mealie.core.root_logger import get_logger | ||||||
| from mealie.services._base_service import BaseService | from mealie.services._base_service import BaseService | ||||||
| @@ -29,7 +30,10 @@ class DefaultEmailSender(ABCEmailSender, BaseService): | |||||||
|             smtp_options["user"] = self.settings.SMTP_USER |             smtp_options["user"] = self.settings.SMTP_USER | ||||||
|         if self.settings.SMTP_PASSWORD: |         if self.settings.SMTP_PASSWORD: | ||||||
|             smtp_options["password"] = self.settings.SMTP_PASSWORD |             smtp_options["password"] = self.settings.SMTP_PASSWORD | ||||||
|         response = message.send(to=email_to, smtp=smtp_options) |         response: SMTPResponse = message.send(to=email_to, smtp=smtp_options) | ||||||
|         logger.info(f"send email result: {response}") |         logger.info(f"send email result: {response}") | ||||||
|  |  | ||||||
|  |         if not response.success: | ||||||
|  |             logger.error(f"send email error: {response.error}") | ||||||
|  |  | ||||||
|         return response.status_code in [250] |         return response.status_code in [250] | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user