mirror of
https://github.com/TandoorRecipes/recipes.git
synced 2026-01-03 13:19:16 -05:00
small fixes
This commit is contained in:
@@ -12,7 +12,7 @@
|
|||||||
<v-window-item v-for="w in recipeWindows" class="pt-1 pb-1">
|
<v-window-item v-for="w in recipeWindows" class="pt-1 pb-1">
|
||||||
<v-row dense>
|
<v-row dense>
|
||||||
<v-col class="pr-0 pl-0" v-for="r in w" :key="r.id">
|
<v-col class="pr-0 pl-0" v-for="r in w" :key="r.id">
|
||||||
<recipe-card :recipe="r" :show_description="true" :show_keywords="true" style="height: 20vh"></recipe-card>
|
<recipe-card :recipe="r" :show_description="true" :show_keywords="true" ></recipe-card>
|
||||||
</v-col>
|
</v-col>
|
||||||
</v-row>
|
</v-row>
|
||||||
</v-window-item>
|
</v-window-item>
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
<template v-if="!props.loading">
|
<template v-if="!props.loading">
|
||||||
|
|
||||||
<router-link :to="{name: 'view_recipe', params: {id: props.recipe.id}}">
|
<router-link :to="{name: 'view_recipe', params: {id: props.recipe.id}}">
|
||||||
<recipe-image :style="{'height': props.height}" :recipe="props.recipe" rounded="lg" class="mr-3 ml-3">
|
<recipe-image :style="{height: props.height}" :recipe="props.recipe" rounded="lg" class="mr-3 ml-3">
|
||||||
|
|
||||||
</recipe-image>
|
</recipe-image>
|
||||||
</router-link>
|
</router-link>
|
||||||
@@ -19,7 +19,7 @@
|
|||||||
<!-- <p class="text-disabled">{{ props.recipe.createdBy.displayName}}</p>-->
|
<!-- <p class="text-disabled">{{ props.recipe.createdBy.displayName}}</p>-->
|
||||||
<keywords-component variant="outlined" :keywords="props.recipe.keywords" :max-keywords="3">
|
<keywords-component variant="outlined" :keywords="props.recipe.keywords" :max-keywords="3">
|
||||||
<template #prepend>
|
<template #prepend>
|
||||||
<v-chip class="mb-1 me-1" size="x-small" label variant="outlined" color="info"
|
<v-chip class="mb-1 me-1" size="x-small" label variant="outlined" color="info"
|
||||||
v-if="!props.recipe.internal">
|
v-if="!props.recipe.internal">
|
||||||
{{ $t('External') }}
|
{{ $t('External') }}
|
||||||
</v-chip>
|
</v-chip>
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ const props = defineProps({
|
|||||||
height: {type: String},
|
height: {type: String},
|
||||||
width: {type: String},
|
width: {type: String},
|
||||||
cover: {type: Boolean, default: true},
|
cover: {type: Boolean, default: true},
|
||||||
rounded: {type: Boolean as PropType<Boolean|String>, default: false},
|
rounded: {type: [Boolean, String], default: false},
|
||||||
})
|
})
|
||||||
|
|
||||||
const image = computed(() => {
|
const image = computed(() => {
|
||||||
|
|||||||
@@ -78,27 +78,19 @@
|
|||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
|
||||||
import {computed, defineComponent, PropType, ref, watch} from 'vue'
|
import {computed, ref, watch} from 'vue'
|
||||||
import {ApiApi, Ingredient, Recipe} from "@/openapi"
|
import {Recipe} from "@/openapi"
|
||||||
import KeywordsBar from "@/components/display/KeywordsBar.vue"
|
|
||||||
import NumberScalerDialog from "@/components/inputs/NumberScalerDialog.vue"
|
import NumberScalerDialog from "@/components/inputs/NumberScalerDialog.vue"
|
||||||
import IngredientsTable from "@/components/display/IngredientsTable.vue";
|
|
||||||
import StepsOverview from "@/components/display/StepsOverview.vue";
|
import StepsOverview from "@/components/display/StepsOverview.vue";
|
||||||
import Step from "@/components/display/Step.vue";
|
import Step from "@/components/display/Step.vue";
|
||||||
import RecipeActivity from "@/components/display/RecipeActivity.vue";
|
import RecipeActivity from "@/components/display/RecipeActivity.vue";
|
||||||
import RecipeContextMenu from "@/components/inputs/RecipeContextMenu.vue";
|
import RecipeContextMenu from "@/components/inputs/RecipeContextMenu.vue";
|
||||||
import KeywordsComponent from "@/components/display/KeywordsBar.vue";
|
import KeywordsComponent from "@/components/display/KeywordsBar.vue";
|
||||||
import RecipeImage from "@/components/display/RecipeImage.vue";
|
import RecipeImage from "@/components/display/RecipeImage.vue";
|
||||||
import PdfViewer from "../../../../vue/src/components/PdfViewer.vue";
|
|
||||||
import ImageViewer from "../../../../vue/src/components/ImageViewer.vue";
|
|
||||||
import ExternalRecipeViewer from "@/components/display/ExternalRecipeViewer.vue";
|
import ExternalRecipeViewer from "@/components/display/ExternalRecipeViewer.vue";
|
||||||
|
|
||||||
const recipe = defineModel<Recipe>({required: true})
|
const recipe = defineModel<Recipe>({required: true})
|
||||||
|
|
||||||
const props = defineProps({
|
|
||||||
|
|
||||||
})
|
|
||||||
|
|
||||||
const servings = ref(1)
|
const servings = ref(1)
|
||||||
const showFullRecipeName = ref(false)
|
const showFullRecipeName = ref(false)
|
||||||
|
|
||||||
|
|||||||
@@ -1,20 +1,22 @@
|
|||||||
import {acceptHMRUpdate, defineStore} from 'pinia'
|
import {acceptHMRUpdate, defineStore} from 'pinia'
|
||||||
import {useStorage} from "@vueuse/core";
|
import {useStorage} from "@vueuse/core";
|
||||||
import {ErrorMessageType, PreparedMessage, useMessageStore} from "@/stores/MessageStore";
|
import {ErrorMessageType, PreparedMessage, useMessageStore} from "@/stores/MessageStore";
|
||||||
import {ApiApi, ServerSettings, Space, Supermarket, UserPreference} from "@/openapi";
|
import {ApiApi, ServerSettings, Space, Supermarket, UserPreference, UserSpace} from "@/openapi";
|
||||||
import {ShoppingGroupingOptions} from "@/types/Shopping";
|
import {ShoppingGroupingOptions} from "@/types/Shopping";
|
||||||
|
import {computed, ComputedRef} from "vue";
|
||||||
|
|
||||||
const DEVICE_SETTINGS_KEY = 'TANDOOR_DEVICE_SETTINGS'
|
const DEVICE_SETTINGS_KEY = 'TANDOOR_DEVICE_SETTINGS'
|
||||||
const USER_PREFERENCE_KEY = 'TANDOOR_USER_PREFERENCE'
|
const USER_PREFERENCE_KEY = 'TANDOOR_USER_PREFERENCE'
|
||||||
const SERVER_SETTINGS_KEY = 'TANDOOR_SERVER_SETTINGS'
|
const SERVER_SETTINGS_KEY = 'TANDOOR_SERVER_SETTINGS'
|
||||||
const ACTIVE_SPACE_KEY = 'TANDOOR_ACTIVE_SPACE'
|
const ACTIVE_SPACE_KEY = 'TANDOOR_ACTIVE_SPACE'
|
||||||
|
const USER_SPACES_KEY = 'TANDOOR_USER_SPACES'
|
||||||
|
|
||||||
class DeviceSettings {
|
class DeviceSettings {
|
||||||
shopping_show_checked_entries = false
|
shopping_show_checked_entries = false
|
||||||
shopping_show_delayed_entries = false
|
shopping_show_delayed_entries = false
|
||||||
shopping_show_selected_supermarket_only = false
|
shopping_show_selected_supermarket_only = false
|
||||||
shopping_selected_grouping = ShoppingGroupingOptions.CATEGORY
|
shopping_selected_grouping = ShoppingGroupingOptions.CATEGORY
|
||||||
shopping_selected_supermarket: Supermarket|null = null
|
shopping_selected_supermarket: Supermarket | null = null
|
||||||
shopping_item_info_created_by = false
|
shopping_item_info_created_by = false
|
||||||
shopping_item_info_mealplan = true
|
shopping_item_info_mealplan = true
|
||||||
shopping_item_info_recipe = true
|
shopping_item_info_recipe = true
|
||||||
@@ -46,6 +48,24 @@ export const useUserPreferenceStore = defineStore('user_preference_store', () =>
|
|||||||
* database user settings, cache in local storage in case application is started offline
|
* database user settings, cache in local storage in case application is started offline
|
||||||
*/
|
*/
|
||||||
let activeSpace = useStorage(ACTIVE_SPACE_KEY, {} as Space)
|
let activeSpace = useStorage(ACTIVE_SPACE_KEY, {} as Space)
|
||||||
|
/**
|
||||||
|
* list of spaces the user has access to and the relevant permissions, cache in local storage in case application is started offline
|
||||||
|
*/
|
||||||
|
let userSpaces = useStorage(USER_SPACES_KEY, [] as UserSpace[])
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* holds the active user space if there is one or null if not
|
||||||
|
*/
|
||||||
|
let activeUserSpace: ComputedRef<null | UserSpace> = computed(() => {
|
||||||
|
let userSpace: null | UserSpace = null
|
||||||
|
userSpaces.value.forEach(us => {
|
||||||
|
if (us.space == activeSpace.value.id) {
|
||||||
|
userSpace = us
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return userSpace
|
||||||
|
})
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* retrieve user settings from DB
|
* retrieve user settings from DB
|
||||||
@@ -102,6 +122,18 @@ export const useUserPreferenceStore = defineStore('user_preference_store', () =>
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* load user spaces
|
||||||
|
*/
|
||||||
|
function loadUserSpaces() {
|
||||||
|
let api = new ApiApi()
|
||||||
|
api.apiUserSpaceList().then(r => {
|
||||||
|
userSpaces.value = r.results
|
||||||
|
}).catch(err => {
|
||||||
|
useMessageStore().addError(ErrorMessageType.FETCH_ERROR, err)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* switch to the given space
|
* switch to the given space
|
||||||
*/
|
*/
|
||||||
@@ -119,18 +151,29 @@ export const useUserPreferenceStore = defineStore('user_preference_store', () =>
|
|||||||
/**
|
/**
|
||||||
* resets all device settings to their default value
|
* resets all device settings to their default value
|
||||||
*/
|
*/
|
||||||
function resetDeviceSettings(){
|
function resetDeviceSettings() {
|
||||||
deviceSettings.value = new DeviceSettings()
|
deviceSettings.value = new DeviceSettings()
|
||||||
}
|
}
|
||||||
|
|
||||||
// always load user settings on first initialization of store
|
// always load settings on first initialization of store
|
||||||
loadUserSettings()
|
loadUserSettings()
|
||||||
// always load server settings on first initialization of store
|
|
||||||
loadServerSettings()
|
loadServerSettings()
|
||||||
// always load active space on first initialization of store
|
|
||||||
loadActiveSpace()
|
loadActiveSpace()
|
||||||
|
loadUserSpaces()
|
||||||
|
|
||||||
return {deviceSettings, userSettings, serverSettings, activeSpace, loadUserSettings, loadServerSettings, updateUserSettings, switchSpace, resetDeviceSettings}
|
return {
|
||||||
|
deviceSettings,
|
||||||
|
userSettings,
|
||||||
|
serverSettings,
|
||||||
|
activeSpace,
|
||||||
|
userSpaces,
|
||||||
|
activeUserSpace,
|
||||||
|
loadUserSettings,
|
||||||
|
loadServerSettings,
|
||||||
|
updateUserSettings,
|
||||||
|
switchSpace,
|
||||||
|
resetDeviceSettings
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
// enable hot reload for store
|
// enable hot reload for store
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
import {ShoppingListEntry} from "@/openapi";
|
import {ShoppingListEntry, Space} from "@/openapi";
|
||||||
import {IShoppingListFood} from "@/types/Shopping";
|
import {IShoppingListFood} from "@/types/Shopping";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* determine if a shopping list entry is delayed
|
* determine if a shopping list entry is delayed
|
||||||
* @param entry
|
* @param entry
|
||||||
*/
|
*/
|
||||||
export function isDelayed(entry: ShoppingListEntry){
|
export function isDelayed(entry: ShoppingListEntry) {
|
||||||
// this function is needed because the openapi typescript fetch client always replaces null with undefined, so delayUntil cant be
|
// this function is needed because the openapi typescript fetch client always replaces null with undefined, so delayUntil cant be
|
||||||
// set back to null once it has been delayed once. This will hopefully be fixed at some point, until then un-delaying will set the date to 1997-1-1 00:00
|
// set back to null once it has been delayed once. This will hopefully be fixed at some point, until then un-delaying will set the date to 1997-1-1 00:00
|
||||||
return entry.delayUntil != null && entry.delayUntil > new Date()
|
return entry.delayUntil != null && entry.delayUntil > new Date()
|
||||||
@@ -14,10 +14,42 @@ export function isDelayed(entry: ShoppingListEntry){
|
|||||||
/**
|
/**
|
||||||
* determine if any entry in a given IShoppingListFood is delayed, if so return true
|
* determine if any entry in a given IShoppingListFood is delayed, if so return true
|
||||||
*/
|
*/
|
||||||
export function isShoppingListFoodDelayed(slf: IShoppingListFood){
|
export function isShoppingListFoodDelayed(slf: IShoppingListFood) {
|
||||||
let hasDelayedEntry = false
|
let hasDelayedEntry = false
|
||||||
slf.entries.forEach(sle => {
|
slf.entries.forEach(sle => {
|
||||||
hasDelayedEntry = hasDelayedEntry || isDelayed(sle)
|
hasDelayedEntry = hasDelayedEntry || isDelayed(sle)
|
||||||
})
|
})
|
||||||
return hasDelayedEntry
|
return hasDelayedEntry
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* checks if the given space is above any of the configured limits
|
||||||
|
* @param space space to check limit for
|
||||||
|
*/
|
||||||
|
export function isSpaceAtLimit(space: Space) {
|
||||||
|
return isSpaceAtUserLimit(space) || isSpaceAtRecipeLimit(space) || isSpaceAtStorageLimit(space)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* checks if the given space is above the user limit
|
||||||
|
* @param space space to check limit for
|
||||||
|
*/
|
||||||
|
export function isSpaceAtUserLimit(space: Space) {
|
||||||
|
return space.maxUsers > space.userCount && space.maxUsers > 0
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* checks if the given space is above the recipe limit
|
||||||
|
* @param space space to check limit for
|
||||||
|
*/
|
||||||
|
export function isSpaceAtRecipeLimit(space: Space) {
|
||||||
|
return space.maxRecipes > space.recipeCount && space.maxRecipes > 0
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* checks if the given space is above the file storage limit
|
||||||
|
* @param space space to check limit for
|
||||||
|
*/
|
||||||
|
export function isSpaceAtStorageLimit(space: Space) {
|
||||||
|
return space.maxFileStorageMb > space.fileSizeMb && space.maxFileStorageMb > 0
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user