fixed times cooked in saved serarch and improved frontend query binding

This commit is contained in:
vabene1111
2025-11-19 21:02:16 +01:00
parent dd56bb4b35
commit 14696e3ce8
3 changed files with 35 additions and 13 deletions

View File

@@ -324,9 +324,9 @@ class RecipeSearch():
self._queryset = self._queryset.annotate(recent=Coalesce(Max(Case(When(pk__in=num_recent_recipes.values('recipe'), then='viewlog__pk'))), Value(0))) self._queryset = self._queryset.annotate(recent=Coalesce(Max(Case(When(pk__in=num_recent_recipes.values('recipe'), then='viewlog__pk'))), Value(0)))
def _favorite_recipes(self): def _favorite_recipes(self):
if self._sort_includes('favorite') or self._timescooked or self._timescooked_gte or self._timescooked_lte: if self._sort_includes('favorite') or self._timescooked is not None or self._timescooked_gte is not None or self._timescooked_lte is not None:
less_than = self._timescooked_lte and not self._sort_includes('-favorite') less_than = self._timescooked_lte and not self._sort_includes('-favorite')
if less_than or self._timescooked == 0: if less_than:
default = 1000 default = 1000
else: else:
default = 0 default = 0
@@ -338,11 +338,11 @@ class RecipeSearch():
) )
self._queryset = self._queryset.annotate(favorite=Coalesce(Subquery(favorite_recipes), default)) self._queryset = self._queryset.annotate(favorite=Coalesce(Subquery(favorite_recipes), default))
if self._timescooked: if self._timescooked is not None:
self._queryset = self._queryset.filter(favorite=self._timescooked) self._queryset = self._queryset.filter(favorite=self._timescooked)
elif self._timescooked_lte: elif self._timescooked_lte is not None:
self._queryset = self._queryset.filter(favorite__lte=int(self._timescooked_lte)).exclude(favorite=0) self._queryset = self._queryset.filter(favorite__lte=int(self._timescooked_lte)).exclude(favorite=0)
elif self._timescooked_gte: elif self._timescooked_gte is not None:
self._queryset = self._queryset.filter(favorite__gte=int(self._timescooked_gte)) self._queryset = self._queryset.filter(favorite__gte=int(self._timescooked_gte))
def keyword_filters(self, **kwargs): def keyword_filters(self, **kwargs):

View File

@@ -184,7 +184,7 @@ import RecipeCard from "@/components/display/RecipeCard.vue";
import {useDisplay} from "vuetify"; import {useDisplay} from "vuetify";
import {useUserPreferenceStore} from "@/stores/UserPreferenceStore"; import {useUserPreferenceStore} from "@/stores/UserPreferenceStore";
import {useRouteQuery} from "@vueuse/router"; import {useRouteQuery} from "@vueuse/router";
import {routeQueryDateTransformer, stringToBool, toNumberArray} from "@/utils/utils"; import {numberOrUndefinedTransformer, routeQueryDateTransformer, stringToBool, toNumberArray} from "@/utils/utils";
import RandomIcon from "@/components/display/RandomIcon.vue"; import RandomIcon from "@/components/display/RandomIcon.vue";
import {VSelect, VTextField, VNumberInput} from "vuetify/components"; import {VSelect, VTextField, VNumberInput} from "vuetify/components";
import RatingField from "@/components/inputs/RatingField.vue"; import RatingField from "@/components/inputs/RatingField.vue";
@@ -759,27 +759,30 @@ const filters = ref({
label: `${t('Rating')} (${t('exact')})`, label: `${t('Rating')} (${t('exact')})`,
hint: '', hint: '',
enabled: false, enabled: false,
clearable: true,
default: undefined, default: undefined,
is: RatingField, is: RatingField,
modelValue: useRouteQuery('rating', undefined, {transform: Number}), modelValue: useRouteQuery('rating', undefined, {transform: numberOrUndefinedTransformer}),
}, },
ratingGte: { ratingGte: {
id: 'ratingGte', id: 'ratingGte',
label: `${t('Rating')} (>=)`, label: `${t('Rating')} (>=)`,
hint: '', hint: '',
enabled: false, enabled: false,
clearable: true,
default: undefined, default: undefined,
is: RatingField, is: RatingField,
modelValue: useRouteQuery('ratingGte', undefined, {transform: Number}), modelValue: useRouteQuery('ratingGte', undefined, {transform: numberOrUndefinedTransformer}),
}, },
ratingLte: { ratingLte: {
id: 'ratingLte', id: 'ratingLte',
label: `${t('Rating')} (<=)`, label: `${t('Rating')} (<=)`,
hint: '', hint: '',
enabled: false, enabled: false,
clearable: true,
default: undefined, default: undefined,
is: RatingField, is: RatingField,
modelValue: useRouteQuery('ratingLte', undefined, {transform: Number}), modelValue: useRouteQuery('ratingLte', undefined, {transform: numberOrUndefinedTransformer}),
}, },
timescooked: { timescooked: {
id: 'timescooked', id: 'timescooked',
@@ -787,26 +790,29 @@ const filters = ref({
hint: 'Recipes that were cooked at least X times', hint: 'Recipes that were cooked at least X times',
enabled: false, enabled: false,
default: undefined, default: undefined,
clearable: true,
is: VNumberInput, is: VNumberInput,
modelValue: useRouteQuery('timescooked', undefined, {transform: Number}), modelValue: useRouteQuery('timescooked', undefined, {transform: numberOrUndefinedTransformer}),
}, },
timescookedGte: { timescookedGte: {
id: 'timescookedGte', id: 'timescookedGte',
label: `${t('times_cooked')} (>=)`, label: `${t('times_cooked')} (>=)`,
hint: '', hint: '',
enabled: false, enabled: false,
clearable: true,
default: undefined, default: undefined,
is: VNumberInput, is: VNumberInput,
modelValue: useRouteQuery('timescookedGte', undefined, {transform: Number}), modelValue: useRouteQuery('timescookedGte', undefined, {transform: numberOrUndefinedTransformer}),
}, },
timescookedLte: { timescookedLte: {
id: 'timescookedLte', id: 'timescookedLte',
label: `${t('times_cooked')} (<=)`, label: `${t('times_cooked')} (<=)`,
hint: '', hint: '',
enabled: false, enabled: false,
clearable: true,
default: undefined, default: undefined,
is: VNumberInput, is: VNumberInput,
modelValue: useRouteQuery('timescookedLte', undefined, {transform: Number}), modelValue: useRouteQuery('timescookedLte', undefined, {transform: numberOrUndefinedTransformer}),
}, },
makenow: { makenow: {
id: 'makenow', id: 'makenow',

View File

@@ -79,4 +79,20 @@ export function stringToBool(param: string): boolean | undefined {
export const routeQueryDateTransformer = { export const routeQueryDateTransformer = {
get: (value: string | null | Date) => ((value == null) ? null : (new Date(value))), get: (value: string | null | Date) => ((value == null) ? null : (new Date(value))),
set: (value: string | null | Date) => ((value == null) ? null : (DateTime.fromJSDate(new Date(value)).toISODate())) set: (value: string | null | Date) => ((value == null) ? null : (DateTime.fromJSDate(new Date(value)).toISODate()))
} }
/**
* routeQueryParam transformer for boolean fields converting string bools to real bools
*/
export const boolOrUndefinedTransformer = {
get: (value: string | null | undefined) => ((value == null) ? undefined : value == 'true'),
set: (value: boolean | null | undefined) => ((value == null) ? undefined : value.toString())
}
/**
* routeQueryParam transformer for number fields converting string numbers to real numbers and allowing undefined for resettable parameters
*/
export const numberOrUndefinedTransformer = {
get: (value: string | null | undefined) => ((value == null) ? undefined : Number(value)),
set: (value: string | null | undefined) => ((value == null) ? undefined : value.toString())
}