export recipes from saved filter

This commit is contained in:
smilerz 2022-02-22 15:18:39 -06:00
parent c1605454dd
commit a7d66fa850
No known key found for this signature in database
GPG Key ID: 39444C7606D47126
5 changed files with 333 additions and 513 deletions

View File

@ -179,6 +179,7 @@ class ImportForm(ImportExportBase):
class ExportForm(ImportExportBase):
recipes = forms.ModelMultipleChoiceField(widget=MultiSelectWidget, queryset=Recipe.objects.none(), required=False)
all = forms.BooleanField(required=False)
filter = forms.IntegerField(required=False)
def __init__(self, *args, **kwargs):
space = kwargs.pop('space')

View File

@ -13,8 +13,8 @@ from cookbook.filters import RecipeFilter
from cookbook.helper.HelperFunctions import Round, str2bool
from cookbook.helper.permission_helper import has_group_permission
from cookbook.managers import DICTIONARY
from cookbook.models import (CookLog, CustomFilter, Food, Keyword, Recipe, SearchFields,
SearchPreference, ViewLog, RecipeBook)
from cookbook.models import (CookLog, CustomFilter, Food, Keyword, Recipe, RecipeBook, SearchFields,
SearchPreference, ViewLog)
from recipes import settings
@ -40,7 +40,7 @@ class RecipeSearch():
self._search_prefs = request.user.searchpreference
else:
self._search_prefs = SearchPreference()
self._string = params.get('query').strip() if params.get('query', None) else None
self._string = self._params.get('query').strip() if self._params.get('query', None) else None
self._rating = self._params.get('rating', None)
self._keywords = {
'or': self._params.get('keywords_or', None) or self._params.get('keywords', None),
@ -205,7 +205,7 @@ class RecipeSearch():
else:
self._queryset = self._queryset.annotate(simularity=Coalesce(Subquery(simularity), 0.0))
if self._sort_includes('score') and self._fulltext_include and self._fuzzy_match is not None:
self._queryset = self._queryset.annotate(score=Sum(F('rank')+F('simularity')))
self._queryset = self._queryset.annotate(score=F('rank')+F('simularity'))
else:
query_filter = Q()
for f in [x + '__unaccent__iexact' if x in self._unaccent_include else x + '__iexact' for x in SearchFields.objects.all().values_list('field', flat=True)]:

View File

@ -11,6 +11,7 @@ from django.utils.translation import gettext as _
from cookbook.forms import ExportForm, ImportExportBase, ImportForm
from cookbook.helper.permission_helper import group_required
from cookbook.helper.recipe_search import RecipeSearch
from cookbook.integration.cheftap import ChefTap
from cookbook.integration.chowdown import Chowdown
from cookbook.integration.cookbookapp import CookBookApp
@ -123,6 +124,9 @@ def export_recipe(request):
recipes = form.cleaned_data['recipes']
if form.cleaned_data['all']:
recipes = Recipe.objects.filter(space=request.space, internal=True).all()
elif filter := form.cleaned_data['filter']:
search = RecipeSearch(request, filter=filter)
recipes = search.get_queryset(Recipe.objects.filter(space=request.space, internal=True))
integration = get_integration(request, form.cleaned_data['type'])

View File

@ -1,11 +1,9 @@
<template>
<div id="app">
<h2>{{ $t('Export') }}</h2>
<h2>{{ $t("Export") }}</h2>
<div class="row">
<div class="col col-md-12">
<br/>
<br />
<!-- TODO get option dynamicaly -->
<select class="form-control" v-model="recipe_app">
<option value="DEFAULT">Default</option>
@ -14,9 +12,9 @@
<option value="PDF">PDF (experimental)</option>
</select>
<br/>
<b-form-checkbox v-model="export_all" @change="disabled_multiselect=$event" name="check-button" switch style="margin-top: 1vh">
{{ $t('All recipes') }}
<br />
<b-form-checkbox v-model="export_all" @change="disabled_multiselect = $event" name="check-button" switch style="margin-top: 1vh">
{{ $t("All recipes") }}
</b-form-checkbox>
<multiselect
@ -35,140 +33,142 @@
id="id_recipes"
:multiple="true"
:loading="recipes_loading"
@search-change="searchRecipes">
@search-change="searchRecipes"
>
</multiselect>
<generic-multiselect
@change="filter = $event.val"
:model="Models.CUSTOM_FILTER"
style="flex-grow: 1; flex-shrink: 1; flex-basis: 0"
:placeholder="$t('Custom Filter')"
:multiple="false"
:limit="50"
/>
<br/>
<button @click="exportRecipe()" class="btn btn-primary shadow-none"><i class="fas fa-file-export"></i> {{ $t('Export') }}
</button>
<br />
<button @click="exportRecipe()" class="btn btn-primary shadow-none"><i class="fas fa-file-export"></i> {{ $t("Export") }}</button>
</div>
</div>
</div>
</template>
<script>
import Vue from 'vue'
import {BootstrapVue} from 'bootstrap-vue'
import Vue from "vue"
import { BootstrapVue } from "bootstrap-vue"
import 'bootstrap-vue/dist/bootstrap-vue.css'
import "bootstrap-vue/dist/bootstrap-vue.css"
import LoadingSpinner from "@/components/LoadingSpinner"
import LoadingSpinner from "@/components/LoadingSpinner";
import {StandardToasts, makeToast, resolveDjangoUrl} from "@/utils/utils";
import Multiselect from "vue-multiselect";
import {ApiApiFactory} from "@/utils/openapi/api.ts";
import axios from "axios";
import { StandardToasts, makeToast, resolveDjangoUrl, ApiMixin } from "@/utils/utils"
import Multiselect from "vue-multiselect"
import GenericMultiselect from "@/components/GenericMultiselect"
import { ApiApiFactory } from "@/utils/openapi/api.ts"
import axios from "axios"
Vue.use(BootstrapVue)
export default {
name: 'ExportView',
name: "ExportView",
/*mixins: [
ResolveUrlMixin,
ToastMixin,
],*/
components: {Multiselect},
components: { Multiselect, GenericMultiselect },
mixins: [ApiMixin],
data() {
return {
export_id: window.EXPORT_ID,
loading: false,
disabled_multiselect: false,
recipe_app: 'DEFAULT',
recipe_app: "DEFAULT",
recipe_list: [],
recipes_loading: false,
recipes: [],
export_all: false,
filter: undefined,
}
},
mounted() {
if(this.export_id)
this.insertRequested()
else
this.searchRecipes('')
if (this.export_id) this.insertRequested()
else this.searchRecipes("")
},
methods: {
insertRequested: function(){
insertRequested: function () {
let apiFactory = new ApiApiFactory()
this.recipes_loading = true
apiFactory.retrieveRecipe(this.export_id).then((response) => {
apiFactory
.retrieveRecipe(this.export_id)
.then((response) => {
this.recipes_loading = false
this.recipe_list.push(response.data)
}).catch((err) => {
})
.catch((err) => {
console.log(err)
StandardToasts.makeStandardToast(StandardToasts.FAIL_FETCH)
}).then(e => this.searchRecipes(''))
})
.then((e) => this.searchRecipes(""))
},
searchRecipes: function (query) {
let apiFactory = new ApiApiFactory()
this.recipes_loading = true
let maxResultLenght = 1000
apiFactory.listRecipes(query, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, 1, maxResultLenght).then((response) => {
this.recipes = response.data.results;
apiFactory
.listRecipes(query, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, 1, maxResultLenght)
.then((response) => {
this.recipes = response.data.results
this.recipes_loading = false
}).catch((err) => {
})
.catch((err) => {
console.log(err)
StandardToasts.makeStandardToast(StandardToasts.FAIL_FETCH)
})
},
exportRecipe: function () {
if (this.recipe_list.length < 1 && this.export_all == false) {
if (this.recipe_list.length < 1 && this.export_all == false && this.filter === undefined) {
makeToast(this.$t("Error"), this.$t("Select at least one recipe"), "danger")
return;
return
}
this.error = undefined
this.loading = true
let formData = new FormData();
formData.append('type', this.recipe_app);
formData.append('all', this.export_all)
let formData = new FormData()
formData.append("type", this.recipe_app)
formData.append("all", this.export_all)
formData.append("filter", this.filter?.id)
for (var i = 0; i < this.recipe_list.length; i++) {
formData.append('recipes', this.recipe_list[i].id);
formData.append("recipes", this.recipe_list[i].id)
}
axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded';
axios.post(resolveDjangoUrl('view_export',), formData).then((response) => {
if (response.data['error'] !== undefined){
makeToast(this.$t("Error"), response.data['error'],"warning")
}else{
window.location.href = resolveDjangoUrl('view_export_response', response.data['export_id'])
axios.defaults.headers.post["Content-Type"] = "application/x-www-form-urlencoded"
axios
.post(resolveDjangoUrl("view_export"), formData)
.then((response) => {
if (response.data["error"] !== undefined) {
makeToast(this.$t("Error"), response.data["error"], "warning")
} else {
window.location.href = resolveDjangoUrl("view_export_response", response.data["export_id"])
}
}).catch((err) => {
})
.catch((err) => {
this.error = err.data
this.loading = false
console.log(err)
makeToast(this.$t("Error"), this.$t("There was an error loading a resource!"), "warning")
})
},
}
},
}
</script>
<style src="vue-multiselect/dist/vue-multiselect.min.css"></style>
<style>
</style>
<style></style>

View File

@ -1,6 +1,6 @@
<template>
<div id="app" style="margin-bottom: 4vh">
<RecipeSwitcher ref="ref_recipe_switcher"/>
<RecipeSwitcher ref="ref_recipe_switcher" />
<div class="row">
<div class="col-12 col-xl-8 col-lg-10 offset-xl-2 offset-lg-1">
<div class="row">
@ -8,21 +8,15 @@
<div class="row justify-content-center">
<div class="col-12 col-lg-10 col-xl-8 mt-3 mb-3">
<b-input-group>
<b-input
class="form-control form-control-lg form-control-borderless form-control-search"
v-model="search.search_input" v-bind:placeholder="$t('Search')"></b-input>
<b-input class="form-control form-control-lg form-control-borderless form-control-search" v-model="search.search_input" v-bind:placeholder="$t('Search')"></b-input>
<b-input-group-append>
<b-button v-b-tooltip.hover :title="$t('show_sql')" @click="showSQL()"
v-if="debug && ui.sql_debug">
<b-button v-b-tooltip.hover :title="$t('show_sql')" @click="showSQL()" v-if="debug && ui.sql_debug">
<i class="fas fa-bug" style="font-size: 1.5em"></i>
</b-button>
<b-button variant="light" v-b-tooltip.hover :title="$t('Random Recipes')"
@click="openRandom()">
<b-button variant="light" v-b-tooltip.hover :title="$t('Random Recipes')" @click="openRandom()">
<i class="fas fa-dice-five" style="font-size: 1.5em"></i>
</b-button>
<b-button v-b-toggle.collapse_advanced_search v-b-tooltip.hover
:title="$t('Advanced Settings')"
v-bind:variant="searchFiltered(true) ? 'danger' : 'primary'">
<b-button v-b-toggle.collapse_advanced_search v-b-tooltip.hover :title="$t('Advanced Settings')" v-bind:variant="searchFiltered(true) ? 'danger' : 'primary'">
<!-- TODO consider changing this icon to a filter -->
<i class="fas fa-caret-down" v-if="!search.advanced_search_visible"></i>
<i class="fas fa-caret-up" v-if="search.advanced_search_visible"></i>
@ -32,18 +26,15 @@
</div>
</div>
<b-collapse id="collapse_advanced_search" class="mt-2 shadow-sm"
v-model="search.advanced_search_visible">
<b-collapse id="collapse_advanced_search" class="mt-2 shadow-sm" v-model="search.advanced_search_visible">
<div class="card">
<div class="card-body p-4">
<div class="row">
<div class="col-md-3">
<a class="btn btn-primary btn-block text-uppercase"
:href="resolveDjangoUrl('new_recipe')">{{ $t("New_Recipe") }}</a>
<a class="btn btn-primary btn-block text-uppercase" :href="resolveDjangoUrl('new_recipe')">{{ $t("New_Recipe") }}</a>
</div>
<div class="col-md-3">
<a class="btn btn-primary btn-block text-uppercase"
:href="resolveDjangoUrl('data_import_url')">{{ $t("Import") }}</a>
<a class="btn btn-primary btn-block text-uppercase" :href="resolveDjangoUrl('data_import_url')">{{ $t("Import") }}</a>
</div>
<div class="col-md-3">
<button
@ -62,186 +53,99 @@
</div>
<div class="col-md-3">
<button id="id_settings_button"
class="btn btn-primary btn-block text-uppercase"><i
class="fas fa-cog fa-lg m-1"></i></button>
<button id="id_settings_button" class="btn btn-primary btn-block text-uppercase"><i class="fas fa-cog fa-lg m-1"></i></button>
</div>
</div>
<b-popover target="id_settings_button" triggers="click" placement="bottom">
<b-tabs content-class="mt-1 text-nowrap" small>
<b-tab :title="$t('Settings')" active :title-link-class="['mx-0']">
<b-form-group v-bind:label="$t('Recently_Viewed')"
label-for="popover-input-1" label-cols="6" class="mb-1">
<b-form-input type="number" v-model="ui.recently_viewed"
id="popover-input-1" size="sm"></b-form-input>
<b-form-group v-bind:label="$t('Recently_Viewed')" label-for="popover-input-1" label-cols="6" class="mb-1">
<b-form-input type="number" v-model="ui.recently_viewed" id="popover-input-1" size="sm"></b-form-input>
</b-form-group>
<b-form-group v-bind:label="$t('Recipes_per_page')"
label-for="popover-input-page-count" label-cols="6"
class="mb-1">
<b-form-input type="number" v-model="ui.page_size"
id="popover-input-page-count"
size="sm"></b-form-input>
<b-form-group v-bind:label="$t('Recipes_per_page')" label-for="popover-input-page-count" label-cols="6" class="mb-1">
<b-form-input type="number" v-model="ui.page_size" id="popover-input-page-count" size="sm"></b-form-input>
</b-form-group>
<b-form-group v-bind:label="$t('Meal_Plan')" label-for="popover-input-2"
label-cols="6" class="mb-1">
<b-form-checkbox switch v-model="ui.show_meal_plan"
id="popover-input-2" size="sm"></b-form-checkbox>
<b-form-group v-bind:label="$t('Meal_Plan')" label-for="popover-input-2" label-cols="6" class="mb-1">
<b-form-checkbox switch v-model="ui.show_meal_plan" id="popover-input-2" size="sm"></b-form-checkbox>
</b-form-group>
<b-form-group v-if="ui.show_meal_plan"
v-bind:label="$t('Meal_Plan_Days')"
label-for="popover-input-5" label-cols="6" class="mb-1">
<b-form-input type="number" v-model="ui.meal_plan_days"
id="popover-input-5" size="sm"></b-form-input>
<b-form-group v-if="ui.show_meal_plan" v-bind:label="$t('Meal_Plan_Days')" label-for="popover-input-5" label-cols="6" class="mb-1">
<b-form-input type="number" v-model="ui.meal_plan_days" id="popover-input-5" size="sm"></b-form-input>
</b-form-group>
<b-form-group v-bind:label="$t('Sort_by_new')"
label-for="popover-input-3" label-cols="6" class="mb-1">
<b-form-checkbox switch v-model="ui.sort_by_new"
id="popover-input-3" size="sm"></b-form-checkbox>
<b-form-group v-bind:label="$t('Sort_by_new')" label-for="popover-input-3" label-cols="6" class="mb-1">
<b-form-checkbox switch v-model="ui.sort_by_new" id="popover-input-3" size="sm"></b-form-checkbox>
</b-form-group>
<div class="row" style="margin-top: 1vh">
<div class="col-12">
<a :href="resolveDjangoUrl('view_settings') + '#search'">{{
$t("Search Settings")
}}</a>
<a :href="resolveDjangoUrl('view_settings') + '#search'">{{ $t("Search Settings") }}</a>
</div>
</div>
</b-tab>
<b-tab :title="$t('fields')" :title-link-class="['mx-0']">
<b-form-group v-bind:label="$t('show_keywords')"
label-for="popover-show_keywords" label-cols="8"
class="mb-1">
<b-form-checkbox switch v-model="ui.show_keywords"
id="popover-show_keywords"
size="sm"></b-form-checkbox>
<b-form-group v-bind:label="$t('show_keywords')" label-for="popover-show_keywords" label-cols="8" class="mb-1">
<b-form-checkbox switch v-model="ui.show_keywords" id="popover-show_keywords" size="sm"></b-form-checkbox>
</b-form-group>
<b-form-group v-bind:label="$t('show_foods')"
label-for="popover-show_foods" label-cols="8"
class="mb-1">
<b-form-checkbox switch v-model="ui.show_foods"
id="popover-show_foods"
size="sm"></b-form-checkbox>
<b-form-group v-bind:label="$t('show_foods')" label-for="popover-show_foods" label-cols="8" class="mb-1">
<b-form-checkbox switch v-model="ui.show_foods" id="popover-show_foods" size="sm"></b-form-checkbox>
</b-form-group>
<b-form-group v-bind:label="$t('show_books')"
label-for="popover-input-show_books" label-cols="8"
class="mb-1">
<b-form-checkbox switch v-model="ui.show_books"
id="popover-input-show_books"
size="sm"></b-form-checkbox>
<b-form-group v-bind:label="$t('show_books')" label-for="popover-input-show_books" label-cols="8" class="mb-1">
<b-form-checkbox switch v-model="ui.show_books" id="popover-input-show_books" size="sm"></b-form-checkbox>
</b-form-group>
<b-form-group v-bind:label="$t('show_rating')"
label-for="popover-show_rating" label-cols="8"
class="mb-1">
<b-form-checkbox switch v-model="ui.show_rating"
id="popover-show_rating"
size="sm"></b-form-checkbox>
<b-form-group v-bind:label="$t('show_rating')" label-for="popover-show_rating" label-cols="8" class="mb-1">
<b-form-checkbox switch v-model="ui.show_rating" id="popover-show_rating" size="sm"></b-form-checkbox>
</b-form-group>
<b-form-group v-bind:label="$t('show_units')"
label-for="popover-show_units" label-cols="8"
class="mb-1">
<b-form-checkbox switch v-model="ui.show_units"
id="popover-show_units"
size="sm"></b-form-checkbox>
<b-form-group v-bind:label="$t('show_units')" label-for="popover-show_units" label-cols="8" class="mb-1">
<b-form-checkbox switch v-model="ui.show_units" id="popover-show_units" size="sm"></b-form-checkbox>
</b-form-group>
<b-form-group v-bind:label="$t('show_filters')"
label-for="popover-show_filters" label-cols="8"
class="mb-1">
<b-form-checkbox switch v-model="ui.show_filters"
id="popover-show_filters"
size="sm"></b-form-checkbox>
<b-form-group v-bind:label="$t('show_filters')" label-for="popover-show_filters" label-cols="8" class="mb-1">
<b-form-checkbox switch v-model="ui.show_filters" id="popover-show_filters" size="sm"></b-form-checkbox>
</b-form-group>
<b-form-group v-bind:label="$t('show_sortby')"
label-for="popover-show_sortby" label-cols="8"
class="mb-1">
<b-form-checkbox switch v-model="ui.show_sortby"
id="popover-show_sortby"
size="sm"></b-form-checkbox>
<b-form-group v-bind:label="$t('show_sortby')" label-for="popover-show_sortby" label-cols="8" class="mb-1">
<b-form-checkbox switch v-model="ui.show_sortby" id="popover-show_sortby" size="sm"></b-form-checkbox>
</b-form-group>
<b-form-group v-bind:label="$t('times_cooked')"
label-for="popover-show_timescooked" label-cols="8"
class="mb-1">
<b-form-checkbox switch v-model="ui.show_timescooked"
id="popover-show_cooked"
size="sm"></b-form-checkbox>
<b-form-group v-bind:label="$t('times_cooked')" label-for="popover-show_timescooked" label-cols="8" class="mb-1">
<b-form-checkbox switch v-model="ui.show_timescooked" id="popover-show_cooked" size="sm"></b-form-checkbox>
</b-form-group>
<b-form-group v-bind:label="$t('make_now')"
label-for="popover-show_makenow" label-cols="8"
class="mb-1">
<b-form-checkbox switch v-model="ui.show_makenow"
id="popover-show_makenow"
size="sm"></b-form-checkbox>
<b-form-group v-bind:label="$t('make_now')" label-for="popover-show_makenow" label-cols="8" class="mb-1">
<b-form-checkbox switch v-model="ui.show_makenow" id="popover-show_makenow" size="sm"></b-form-checkbox>
</b-form-group>
<b-form-group v-bind:label="$t('last_cooked')"
label-for="popover-show_cookedon" label-cols="8"
class="mb-1">
<b-form-checkbox switch v-model="ui.show_cookedon"
id="popover-show_cookedon"
size="sm"></b-form-checkbox>
<b-form-group v-bind:label="$t('last_cooked')" label-for="popover-show_cookedon" label-cols="8" class="mb-1">
<b-form-checkbox switch v-model="ui.show_cookedon" id="popover-show_cookedon" size="sm"></b-form-checkbox>
</b-form-group>
<b-form-group v-bind:label="$t('last_viewed')"
label-for="popover-show_viewedon" label-cols="8"
class="mb-1">
<b-form-checkbox switch v-model="ui.show_viewedon"
id="popover-show_viewedon"
size="sm"></b-form-checkbox>
<b-form-group v-bind:label="$t('last_viewed')" label-for="popover-show_viewedon" label-cols="8" class="mb-1">
<b-form-checkbox switch v-model="ui.show_viewedon" id="popover-show_viewedon" size="sm"></b-form-checkbox>
</b-form-group>
<b-form-group v-bind:label="$t('created_on')"
label-for="popover-show_createdon" label-cols="8"
class="mb-1">
<b-form-checkbox switch v-model="ui.show_createdon"
id="popover-show_createdon"
size="sm"></b-form-checkbox>
<b-form-group v-bind:label="$t('created_on')" label-for="popover-show_createdon" label-cols="8" class="mb-1">
<b-form-checkbox switch v-model="ui.show_createdon" id="popover-show_createdon" size="sm"></b-form-checkbox>
</b-form-group>
<b-form-group v-bind:label="$t('updatedon')"
label-for="popover-show_updatedon" label-cols="8"
class="mb-1">
<b-form-checkbox switch v-model="ui.show_updatedon"
id="popover-show_updatedon"
size="sm"></b-form-checkbox>
<b-form-group v-bind:label="$t('updatedon')" label-for="popover-show_updatedon" label-cols="8" class="mb-1">
<b-form-checkbox switch v-model="ui.show_updatedon" id="popover-show_updatedon" size="sm"></b-form-checkbox>
</b-form-group>
</b-tab>
<b-tab :title="$t('advanced')" :title-link-class="['mx-0']">
<b-form-group v-bind:label="$t('remember_search')"
label-for="popover-rem-search" label-cols="8"
class="mb-1">
<b-form-checkbox switch v-model="ui.remember_search"
id="popover-rem-search"
size="sm"></b-form-checkbox>
<b-form-group v-bind:label="$t('remember_search')" label-for="popover-rem-search" label-cols="8" class="mb-1">
<b-form-checkbox switch v-model="ui.remember_search" id="popover-rem-search" size="sm"></b-form-checkbox>
</b-form-group>
<b-form-group v-if="ui.remember_search"
v-bind:label="$t('remember_hours')"
label-for="popover-input-rem-hours" label-cols="8"
class="mb-1">
<b-form-input type="number" v-model="ui.remember_hours"
id="popover-rem-hours" size="sm"></b-form-input>
<b-form-group v-if="ui.remember_search" v-bind:label="$t('remember_hours')" label-for="popover-input-rem-hours" label-cols="8" class="mb-1">
<b-form-input type="number" v-model="ui.remember_hours" id="popover-rem-hours" size="sm"></b-form-input>
</b-form-group>
<b-form-group v-bind:label="$t('tree_select')"
label-for="popover-input-treeselect" label-cols="8"
class="mb-1">
<b-form-checkbox switch v-model="ui.tree_select"
id="popover-input-treeselect"
size="sm"></b-form-checkbox>
<b-form-group v-bind:label="$t('tree_select')" label-for="popover-input-treeselect" label-cols="8" class="mb-1">
<b-form-checkbox switch v-model="ui.tree_select" id="popover-input-treeselect" size="sm"></b-form-checkbox>
</b-form-group>
<b-form-group v-if="debug" v-bind:label="$t('sql_debug')"
label-for="popover-input-sqldebug" label-cols="8"
class="mb-1">
<b-form-checkbox switch v-model="ui.sql_debug"
id="popover-input-sqldebug"
size="sm"></b-form-checkbox>
<b-form-group v-if="debug" v-bind:label="$t('sql_debug')" label-for="popover-input-sqldebug" label-cols="8" class="mb-1">
<b-form-checkbox switch v-model="ui.sql_debug" id="popover-input-sqldebug" size="sm"></b-form-checkbox>
</b-form-group>
</b-tab>
</b-tabs>
<div class="row" style="margin-top: 1vh">
<div class="col-12" style="text-align: right">
<b-button size="sm" variant="secondary" style="margin-right: 8px"
@click="$root.$emit('bv::hide::popover')">{{ $t("Close") }}
</b-button>
<b-button size="sm" variant="secondary" style="margin-right: 8px" @click="$root.$emit('bv::hide::popover')">{{ $t("Close") }} </b-button>
</div>
</div>
</b-popover>
@ -281,23 +185,18 @@
<h6 class="mb-0" v-if="ui.expert_mode && search.keywords_fields > 1">
{{ $t("Keywords") }}
</h6>
<span class="text-sm-left text-warning"
v-if="ui.expert_mode && search.keywords_fields > 1 && hasDuplicateFilter(search.search_keywords, search.keywords_fields)">{{
<span class="text-sm-left text-warning" v-if="ui.expert_mode && search.keywords_fields > 1 && hasDuplicateFilter(search.search_keywords, search.keywords_fields)">{{
$t("warning_duplicate_filter")
}}</span>
<div class="row" v-if="ui.show_keywords">
<div class="col-12">
<b-input-group class="mt-2" v-for="(k, a) in keywordFields" :key="a">
<template #prepend v-if="ui.expert_mode">
<b-input-group-text style="width: 3em"
@click="addField('keywords', k)">
<i class="fas fa-plus-circle text-primary"
v-if="k == search.keywords_fields && k < 4"/>
<b-input-group-text style="width: 3em" @click="addField('keywords', k)">
<i class="fas fa-plus-circle text-primary" v-if="k == search.keywords_fields && k < 4" />
</b-input-group-text>
<b-input-group-text style="width: 3em"
@click="removeField('keywords', k)">
<i class="fas fa-minus-circle text-primary"
v-if="k == search.keywords_fields && k > 1"/>
<b-input-group-text style="width: 3em" @click="removeField('keywords', k)">
<i class="fas fa-minus-circle text-primary" v-if="k == search.keywords_fields && k > 1" />
</b-input-group-text>
</template>
<treeselect
@ -334,20 +233,14 @@
switch
style="width: 4em"
>
<span class="text-uppercase"
v-if="search.search_keywords[a].operator">{{
$t("or")
}}</span>
<span class="text-uppercase" v-if="search.search_keywords[a].operator">{{ $t("or") }}</span>
<span class="text-uppercase" v-else>{{ $t("and") }}</span>
</b-form-checkbox>
</b-input-group-text>
</b-input-group-append>
<b-input-group-append v-if="ui.expert_mode">
<b-input-group-text>
<b-form-checkbox v-model="search.search_keywords[a].not"
name="check-button"
@change="refreshData(false)"
class="shadow-none">
<b-form-checkbox v-model="search.search_keywords[a].not" name="check-button" @change="refreshData(false)" class="shadow-none">
<span class="text-uppercase">{{ $t("not") }}</span>
</b-form-checkbox>
</b-input-group-text>
@ -360,23 +253,18 @@
<h6 class="mt-2 mb-0" v-if="ui.expert_mode && search.foods_fields > 1">
{{ $t("Foods") }}
</h6>
<span class="text-sm-left text-warning"
v-if="ui.expert_mode && search.foods_fields > 1 && hasDuplicateFilter(search.search_foods, search.foods_fields)">{{
<span class="text-sm-left text-warning" v-if="ui.expert_mode && search.foods_fields > 1 && hasDuplicateFilter(search.search_foods, search.foods_fields)">{{
$t("warning_duplicate_filter")
}}</span>
<div class="row" v-if="ui.show_foods">
<div class="col-12">
<b-input-group class="mt-2" v-for="(f, i) in foodFields" :key="i">
<template #prepend v-if="ui.expert_mode">
<b-input-group-text style="width: 3em"
@click="addField('foods', f)">
<i class="fas fa-plus-circle text-primary"
v-if="f == search.foods_fields && f < 4"/>
<b-input-group-text style="width: 3em" @click="addField('foods', f)">
<i class="fas fa-plus-circle text-primary" v-if="f == search.foods_fields && f < 4" />
</b-input-group-text>
<b-input-group-text style="width: 3em"
@click="removeField('foods', f)">
<i class="fas fa-minus-circle text-primary"
v-if="f == search.foods_fields && f > 1"/>
<b-input-group-text style="width: 3em" @click="removeField('foods', f)">
<i class="fas fa-minus-circle text-primary" v-if="f == search.foods_fields && f > 1" />
</b-input-group-text>
</template>
<treeselect
@ -405,24 +293,15 @@
/>
<b-input-group-append>
<b-input-group-text>
<b-form-checkbox v-model="search.search_foods[i].operator"
name="check-button"
@change="refreshData(false)"
class="shadow-none" switch style="width: 4em">
<span class="text-uppercase"
v-if="search.search_foods[i].operator">{{
$t("or")
}}</span>
<b-form-checkbox v-model="search.search_foods[i].operator" name="check-button" @change="refreshData(false)" class="shadow-none" switch style="width: 4em">
<span class="text-uppercase" v-if="search.search_foods[i].operator">{{ $t("or") }}</span>
<span class="text-uppercase" v-else>{{ $t("and") }}</span>
</b-form-checkbox>
</b-input-group-text>
</b-input-group-append>
<b-input-group-append v-if="ui.expert_mode">
<b-input-group-text>
<b-form-checkbox v-model="search.search_foods[i].not"
name="check-button"
@change="refreshData(false)"
class="shadow-none">
<b-form-checkbox v-model="search.search_foods[i].not" name="check-button" @change="refreshData(false)" class="shadow-none">
<span class="text-uppercase">{{ $t("not") }}</span>
</b-form-checkbox>
</b-input-group-text>
@ -435,23 +314,18 @@
<h6 class="mt-2 mb-0" v-if="ui.expert_mode && search.books_fields > 1">
{{ $t("Books") }}
</h6>
<span class="text-sm-left text-warning"
v-if="ui.expert_mode && search.books_fields > 1 && hasDuplicateFilter(search.search_books, search.books_fields)">{{
<span class="text-sm-left text-warning" v-if="ui.expert_mode && search.books_fields > 1 && hasDuplicateFilter(search.search_books, search.books_fields)">{{
$t("warning_duplicate_filter")
}}</span>
<div class="row" v-if="ui.show_books">
<div class="col-12">
<b-input-group class="mt-2" v-for="(b, i) in bookFields" :key="i">
<template #prepend v-if="ui.expert_mode">
<b-input-group-text style="width: 3em"
@click="addField('books', b)">
<i class="fas fa-plus-circle text-primary"
v-if="b == search.books_fields && b < 4"/>
<b-input-group-text style="width: 3em" @click="addField('books', b)">
<i class="fas fa-plus-circle text-primary" v-if="b == search.books_fields && b < 4" />
</b-input-group-text>
<b-input-group-text style="width: 3em"
@click="removeField('books', b)">
<i class="fas fa-minus-circle text-primary"
v-if="b == search.books_fields && b > 1"/>
<b-input-group-text style="width: 3em" @click="removeField('books', b)">
<i class="fas fa-minus-circle text-primary" v-if="b == search.books_fields && b > 1" />
</b-input-group-text>
</template>
<generic-multiselect
@ -465,24 +339,15 @@
></generic-multiselect>
<b-input-group-append>
<b-input-group-text>
<b-form-checkbox v-model="search.search_books[i].operator"
name="check-button"
@change="refreshData(false)"
class="shadow-none" style="width: 4em" switch>
<span class="text-uppercase"
v-if="search.search_books[i].operator">{{
$t("or")
}}</span>
<b-form-checkbox v-model="search.search_books[i].operator" name="check-button" @change="refreshData(false)" class="shadow-none" style="width: 4em" switch>
<span class="text-uppercase" v-if="search.search_books[i].operator">{{ $t("or") }}</span>
<span class="text-uppercase" v-else>{{ $t("and") }}</span>
</b-form-checkbox>
</b-input-group-text>
</b-input-group-append>
<b-input-group-append v-if="ui.expert_mode">
<b-input-group-text>
<b-form-checkbox v-model="search.search_books[i].not"
name="check-button"
@change="refreshData(false)"
class="shadow-none">
<b-form-checkbox v-model="search.search_books[i].not" name="check-button" @change="refreshData(false)" class="shadow-none">
<span class="text-uppercase">{{ $t("not") }}</span>
</b-form-checkbox>
</b-input-group-text>
@ -506,12 +371,8 @@
/>
<b-input-group-append>
<b-input-group-text>
<b-form-checkbox v-model="search.search_rating_gte"
name="check-button"
@change="refreshData(false)"
class="shadow-none" switch style="width: 4em">
<span class="text-uppercase"
v-if="search.search_rating_gte">&gt;=</span>
<b-form-checkbox v-model="search.search_rating_gte" name="check-button" @change="refreshData(false)" class="shadow-none" switch style="width: 4em">
<span class="text-uppercase" v-if="search.search_rating_gte">&gt;=</span>
<span class="text-uppercase" v-else>&lt;=</span>
</b-form-checkbox>
</b-input-group-text>
@ -534,13 +395,8 @@
></generic-multiselect>
<b-input-group-append>
<b-input-group-text>
<b-form-checkbox v-model="search.search_units_or"
name="check-button"
@change="refreshData(false)"
class="shadow-none" style="width: 4em" switch>
<span class="text-uppercase" v-if="search.search_units_or">{{
$t("or")
}}</span>
<b-form-checkbox v-model="search.search_units_or" name="check-button" @change="refreshData(false)" class="shadow-none" style="width: 4em" switch>
<span class="text-uppercase" v-if="search.search_units_or">{{ $t("or") }}</span>
<span class="text-uppercase" v-else>{{ $t("and") }}</span>
</b-form-checkbox>
</b-input-group-text>
@ -550,23 +406,17 @@
</div>
<!-- special switches -->
<div class="row g-0"
v-if="ui.show_timescooked || ui.show_makenow || ui.show_cookedon">
<div class="row g-0" v-if="ui.show_timescooked || ui.show_makenow || ui.show_cookedon">
<div class="col-12">
<b-input-group class="mt-2">
<!-- times cooked -->
<b-input-group-prepend is-text v-if="ui.show_timescooked">
{{ $t("times_cooked") }}
</b-input-group-prepend>
<b-form-input id="timescooked" type="number" min="0"
v-model="search.timescooked"
v-if="ui.show_timescooked"></b-form-input>
<b-form-input id="timescooked" type="number" min="0" v-model="search.timescooked" v-if="ui.show_timescooked"></b-form-input>
<b-input-group-append v-if="ui.show_timescooked">
<b-input-group-text>
<b-form-checkbox v-model="search.timescooked_gte"
name="check-button"
@change="refreshData(false)"
class="shadow-none" switch style="width: 4em">
<b-form-checkbox v-model="search.timescooked_gte" name="check-button" @change="refreshData(false)" class="shadow-none" switch style="width: 4em">
<span class="text-uppercase" v-if="search.timescooked_gte">&gt;=</span>
<span class="text-uppercase" v-else>&lt;=</span>
</b-form-checkbox>
@ -585,10 +435,7 @@
@input="refreshData(false)"
/>
<b-input-group-text>
<b-form-checkbox v-model="search.cookedon_gte"
name="check-button"
@change="refreshData(false)"
class="shadow-none" switch style="width: 4em">
<b-form-checkbox v-model="search.cookedon_gte" name="check-button" @change="refreshData(false)" class="shadow-none" switch style="width: 4em">
<span class="text-uppercase" v-if="search.cookedon_gte">&gt;=</span>
<span class="text-uppercase" v-else>&lt;=</span>
</b-form-checkbox>
@ -608,10 +455,7 @@
@input="refreshData(false)"
/>
<b-input-group-text>
<b-form-checkbox v-model="search.createdon_gte"
name="check-button"
@change="refreshData(false)"
class="shadow-none" switch style="width: 4em">
<b-form-checkbox v-model="search.createdon_gte" name="check-button" @change="refreshData(false)" class="shadow-none" switch style="width: 4em">
<span class="text-uppercase" v-if="search.createdon_gte">&gt;=</span>
<span class="text-uppercase" v-else>&lt;=</span>
</b-form-checkbox>
@ -629,10 +473,7 @@
@input="refreshData(false)"
/>
<b-input-group-text>
<b-form-checkbox v-model="search.viewedon_gte"
name="check-button"
@change="refreshData(false)"
class="shadow-none" switch style="width: 4em">
<b-form-checkbox v-model="search.viewedon_gte" name="check-button" @change="refreshData(false)" class="shadow-none" switch style="width: 4em">
<span class="text-uppercase" v-if="search.viewedon_gte">&gt;=</span>
<span class="text-uppercase" v-else>&lt;=</span>
</b-form-checkbox>
@ -650,10 +491,7 @@
@input="refreshData(false)"
/>
<b-input-group-text>
<b-form-checkbox v-model="search.updatedon_gte"
name="check-button"
@change="refreshData(false)"
class="shadow-none" switch style="width: 4em">
<b-form-checkbox v-model="search.updatedon_gte" name="check-button" @change="refreshData(false)" class="shadow-none" switch style="width: 4em">
<span class="text-uppercase" v-if="search.updatedon_gte">&gt;=</span>
<span class="text-uppercase" v-else>&lt;=</span>
</b-form-checkbox>
@ -662,9 +500,7 @@
<b-input-group-append v-if="ui.show_makenow">
<b-input-group-text>
{{ $t("make_now") }}
<b-form-checkbox v-model="search.makenow" name="check-button"
@change="refreshData(false)"
class="shadow-none" switch style="width: 4em"/>
<b-form-checkbox v-model="search.makenow" name="check-button" @change="refreshData(false)" class="shadow-none" switch style="width: 4em" />
</b-input-group-text>
</b-input-group-append>
</b-input-group>
@ -674,16 +510,14 @@
<!-- Buttons -->
<div class="row justify-content-end small">
<div class="col-auto">
<b-button class="my-0" variant="link" size="sm"
@click="search.explain_visible = !search.explain_visible">
<b-button class="my-0" variant="link" size="sm" @click="search.explain_visible = !search.explain_visible">
<div v-if="!search.explain_visible">
<i class="far fa-eye"></i>
{{ $t("explain") }}
</div>
<div v-else><i class="far fa-eye-slash"></i> {{ $t("explain") }}</div>
</b-button>
<b-button class="my-0" variant="link" size="sm"
@click="ui.expert_mode = !ui.expert_mode">
<b-button class="my-0" variant="link" size="sm" @click="ui.expert_mode = !ui.expert_mode">
<div v-if="!ui.expert_mode">
<i class="fas fa-circle"></i>
{{ $t("expert_mode") }}
@ -706,21 +540,20 @@
<!-- TODO find a way to localize this that works without explaining localization to each language translator -->
Show all recipes that are matched
<span v-if="search.search_input">
by <i>{{ search.search_input }}</i> <br/>
by <i>{{ search.search_input }}</i> <br />
</span>
<span v-else> without any search term <br/> </span>
<span v-else> without any search term <br /> </span>
<span v-if="search.search_internal"> and are <span class="text-success">internal</span> <br/></span>
<span v-if="search.search_internal"> and are <span class="text-success">internal</span> <br /></span>
<span v-for="k in search.search_keywords" v-bind:key="k.id">
<template v-if="k.items.length > 0">
and
<b v-if="k.not">don't</b>
contain
<b v-if="k.operator">any</b><b
v-else>all</b> of the following <span class="text-success">keywords</span>:
<b v-if="k.operator">any</b><b v-else>all</b> of the following <span class="text-success">keywords</span>:
<i>{{ k.items.flatMap((x) => x.name).join(", ") }}</i>
<br/>
<br />
</template>
</span>
@ -729,11 +562,9 @@
and
<b v-if="k.not">don't</b>
contain
<b v-if="k.operator">any</b><b
v-else>all</b> of the following <span
class="text-success">foods</span>:
<b v-if="k.operator">any</b><b v-else>all</b> of the following <span class="text-success">foods</span>:
<i>{{ k.items.flatMap((x) => x.name).join(", ") }}</i>
<br/>
<br />
</template>
</span>
@ -742,48 +573,40 @@
and
<b v-if="k.not">don't</b>
contain
<b v-if="k.operator">any</b><b
v-else>all</b> of the following <span
class="text-success">books</span>:
<b v-if="k.operator">any</b><b v-else>all</b> of the following <span class="text-success">books</span>:
<i>{{ k.items.flatMap((x) => x.name).join(", ") }}</i>
<br/>
<br />
</template>
</span>
<span v-if="search.makenow"> and you can <span class="text-success">make right now</span> (based on the on hand flag) <br/></span>
<span v-if="search.makenow"> and you can <span class="text-success">make right now</span> (based on the on hand flag) <br /></span>
<span v-if="search.search_units.length > 0">
and contain <b v-if="search.search_units_or">any</b><b
v-else>all</b> of the following <span
class="text-success">units</span>:
and contain <b v-if="search.search_units_or">any</b><b v-else>all</b> of the following <span class="text-success">units</span>:
<i>{{ search.search_units.flatMap((x) => x.name).join(", ") }}</i
><br/>
><br />
</span>
<span v-if="search.search_rating !== undefined">
and have a <span class="text-success">rating</span> <template
v-if="search.search_rating_gte">greater than</template><template
v-else> less than</template> or
equal to {{ search.search_rating }}<br/>
and have a <span class="text-success">rating</span> <template v-if="search.search_rating_gte">greater than</template><template v-else> less than</template> or
equal to {{ search.search_rating }}<br />
</span>
<span v-if="search.lastcooked !== undefined">
and have been <span class="text-success">last cooked</span> <template
v-if="search.lastcooked_gte"> after</template><template v-else> before</template>
and have been <span class="text-success">last cooked</span> <template v-if="search.lastcooked_gte"> after</template><template v-else> before</template>
<i>{{ search.lastcooked }}</i
><br/>
><br />
</span>
<span v-if="search.timescooked !== undefined">
and have <span class="text-success">been cooked</span> <template
v-if="search.timescooked_gte"> at least</template><template v-else> less than</template> or
equal to<i>{{ search.timescooked }}</i> times <br/>
and have <span class="text-success">been cooked</span> <template v-if="search.timescooked_gte"> at least</template><template v-else> less than</template> or
equal to<i>{{ search.timescooked }}</i> times <br />
</span>
<span v-if="search.sort_order.length > 0">
<span class="text-success">order</span> by
<i>{{ search.sort_order.flatMap((x) => x.text).join(", ") }}</i>
<br/>
<br />
</span>
</div>
</div>
@ -797,8 +620,7 @@
<div v-if="recipes.length > 0">
<div class="row align-content-center">
<div class="col col-md-6" style="margin-top: 2vh">
<b-dropdown id="sortby" :text="sortByLabel" variant="link"
toggle-class="text-decoration-none " class="m-0 p-0">
<b-dropdown id="sortby" :text="sortByLabel" variant="link" toggle-class="text-decoration-none " class="m-0 p-0">
<div v-for="o in sortOptions" :key="o.id">
<b-dropdown-item
v-on:click="
@ -813,9 +635,7 @@
</div>
<div class="col col-md-6 text-right" style="margin-top: 2vh">
<span class="text-muted">
{{ $t("Page") }} {{ search.pagination_page }}/{{
Math.ceil(pagination_count / ui.page_size)
}}
{{ $t("Page") }} {{ search.pagination_page }}/{{ Math.ceil(pagination_count / ui.page_size) }}
<a href="#" @click="resetSearch()"><i class="fas fa-times-circle"></i> {{ $t("Reset") }}</a>
</span>
</div>
@ -823,24 +643,25 @@
<div class="row">
<div class="col col-md-12">
<div
style="display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); grid-gap: 0.8rem">
<div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); grid-gap: 0.8rem">
<template v-if="!searchFiltered()">
<recipe-card v-bind:key="`mp_${m.id}`" v-for="m in meal_plans" :recipe="m.recipe"
:meal_plan="m" :footer_text="m.meal_type_name"
footer_icon="far fa-calendar-alt"></recipe-card>
<recipe-card
v-bind:key="`mp_${m.id}`"
v-for="m in meal_plans"
:recipe="m.recipe"
:meal_plan="m"
:footer_text="m.meal_type_name"
footer_icon="far fa-calendar-alt"
></recipe-card>
</template>
<recipe-card v-for="r in recipes" v-bind:key="r.id" :recipe="r"
:footer_text="isRecentOrNew(r)[0]"
:footer_icon="isRecentOrNew(r)[1]"></recipe-card>
<recipe-card v-for="r in recipes" v-bind:key="r.id" :recipe="r" :footer_text="isRecentOrNew(r)[0]" :footer_icon="isRecentOrNew(r)[1]"></recipe-card>
</div>
</div>
</div>
<div class="row" style="margin-top: 2vh" v-if="!random_search">
<div class="col col-md-12">
<b-pagination pills v-model="search.pagination_page" :total-rows="pagination_count"
:per-page="ui.page_size" @change="pageChange" align="center"></b-pagination>
<b-pagination pills v-model="search.pagination_page" :total-rows="pagination_count" :per-page="ui.page_size" @change="pageChange" align="center"></b-pagination>
</div>
</div>
<div class="col-md-2 d-none d-md-block"></div>
@ -848,9 +669,8 @@
<div v-if="recipes.length < 1 && !recipes_loading">
<div class="row mt-5">
<div class="col col-md-12 text-center">
<h4 class="text-muted"><i class="far fa-eye"></i> {{ $t('search_no_recipes') }}</h4>
<h4 class="text-muted"><i class="far fa-eye"></i> {{ $t("search_no_recipes") }}</h4>
</div>
</div>
<div class="row mt-2">
@ -858,47 +678,41 @@
<b-card-group deck>
<b-card v-bind:title="$t('Import')" class="text-center">
<b-card-text>
{{ $t('search_import_help_text') }}
{{ $t("search_import_help_text") }}
</b-card-text>
<b-button variant="primary" :href="resolveDjangoUrl('data_import_url')"><i
class="fas fa-file-import"></i> {{ $t('Import') }}
</b-button>
<b-button variant="primary" :href="resolveDjangoUrl('data_import_url')"><i class="fas fa-file-import"></i> {{ $t("Import") }} </b-button>
</b-card>
<b-card v-bind:title="$t('Create')" class="text-center">
<b-card-text>
{{ $t('search_create_help_text') }}
{{ $t("search_create_help_text") }}
</b-card-text>
<b-button variant="primary" :href="resolveDjangoUrl('new_recipe')"><i
class="fas fa-plus"></i> {{ $t('Create') }}
</b-button>
<b-button variant="primary" :href="resolveDjangoUrl('new_recipe')"><i class="fas fa-plus"></i> {{ $t("Create") }} </b-button>
</b-card>
</b-card-group>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import Vue from "vue"
import {BootstrapVue} from "bootstrap-vue"
import { BootstrapVue } from "bootstrap-vue"
import VueCookies from "vue-cookies"
import "bootstrap-vue/dist/bootstrap-vue.css"
import moment from "moment"
import _debounce from "lodash/debounce"
import Multiselect from "vue-multiselect"
import {Treeselect, LOAD_CHILDREN_OPTIONS} from "@riophae/vue-treeselect"
import { Treeselect, LOAD_CHILDREN_OPTIONS } from "@riophae/vue-treeselect"
import "@riophae/vue-treeselect/dist/vue-treeselect.css"
import {ApiMixin, ResolveUrlMixin, StandardToasts, ToastMixin} from "@/utils/utils"
import { ApiMixin, ResolveUrlMixin, StandardToasts, ToastMixin } from "@/utils/utils"
import LoadingSpinner from "@/components/LoadingSpinner" // TODO: is this deprecated?
import RecipeCard from "@/components/RecipeCard"
import GenericMultiselect from "@/components/GenericMultiselect"
@ -913,13 +727,13 @@ let UI_COOKIE_NAME = "ui_search_settings"
export default {
name: "RecipeSearchView",
mixins: [ResolveUrlMixin, ApiMixin, ToastMixin],
components: {GenericMultiselect, RecipeCard, Treeselect, RecipeSwitcher, Multiselect},
components: { GenericMultiselect, RecipeCard, Treeselect, RecipeSwitcher, Multiselect },
data() {
return {
// this.Models and this.Actions inherited from ApiMixin
recipes: [],
recipes_loading: true,
facets: {Books: [], Foods: [], Keywords: []},
facets: { Books: [], Foods: [], Keywords: [] },
meal_plans: [],
last_viewed_recipes: [],
sortMenu: false,
@ -930,22 +744,22 @@ export default {
search_input: "",
search_internal: false,
search_keywords: [
{items: [], operator: true, not: false},
{items: [], operator: false, not: false},
{items: [], operator: true, not: true},
{items: [], operator: false, not: true},
{ items: [], operator: true, not: false },
{ items: [], operator: false, not: false },
{ items: [], operator: true, not: true },
{ items: [], operator: false, not: true },
],
search_foods: [
{items: [], operator: true, not: false},
{items: [], operator: false, not: false},
{items: [], operator: true, not: true},
{items: [], operator: false, not: true},
{ items: [], operator: true, not: false },
{ items: [], operator: false, not: false },
{ items: [], operator: true, not: true },
{ items: [], operator: false, not: true },
],
search_books: [
{items: [], operator: true, not: false},
{items: [], operator: false, not: false},
{items: [], operator: true, not: true},
{items: [], operator: false, not: true},
{ items: [], operator: true, not: false },
{ items: [], operator: false, not: false },
{ items: [], operator: true, not: true },
{ items: [], operator: false, not: true },
],
search_units: [],
search_units_or: true,
@ -1054,12 +868,12 @@ export default {
}
return [
{id: 5, label: "⭐⭐⭐⭐⭐" + ratingCount(this.facets.Ratings?.["5.0"] ?? 0) + label(5)},
{id: 4, label: "⭐⭐⭐⭐ " + ratingCount(this.facets.Ratings?.["4.0"] ?? 0) + label()},
{id: 3, label: "⭐⭐⭐ " + ratingCount(this.facets.Ratings?.["3.0"] ?? 0) + label()},
{id: 2, label: "⭐⭐ " + ratingCount(this.facets.Ratings?.["2.0"] ?? 0) + label()},
{id: 1, label: "⭐ " + ratingCount(this.facets.Ratings?.["1.0"] ?? 0) + label(1)},
{id: 0, label: this.$t("Unrated") + ratingCount(this.facets.Ratings?.["0.0"] ?? 0)},
{ id: 5, label: "⭐⭐⭐⭐⭐" + ratingCount(this.facets.Ratings?.["5.0"] ?? 0) + label(5) },
{ id: 4, label: "⭐⭐⭐⭐ " + ratingCount(this.facets.Ratings?.["4.0"] ?? 0) + label() },
{ id: 3, label: "⭐⭐⭐ " + ratingCount(this.facets.Ratings?.["3.0"] ?? 0) + label() },
{ id: 2, label: "⭐⭐ " + ratingCount(this.facets.Ratings?.["2.0"] ?? 0) + label() },
{ id: 1, label: "⭐ " + ratingCount(this.facets.Ratings?.["1.0"] ?? 0) + label(1) },
{ id: 0, label: this.$t("Unrated") + ratingCount(this.facets.Ratings?.["0.0"] ?? 0) },
]
},
keywordFields: function () {
@ -1122,22 +936,22 @@ export default {
this.facets.Keywords = []
for (let x of urlParams.getAll("keyword")) {
this.search.search_keywords[0].items.push(Number.parseInt(x))
this.facets.Keywords.push({id: x, name: "loading..."})
this.facets.Keywords.push({ id: x, name: "loading..." })
}
}
// TODO: figure out how to find nested items and load keyword/food children for that branch
// probably a backend change in facets to pre-load children of nested items
for (let x of this.search.search_foods.map((x) => x.items).flat()) {
this.facets.Foods.push({id: x, name: "loading..."})
this.facets.Foods.push({ id: x, name: "loading..." })
}
for (let x of this.search.search_keywords.map((x) => x.items).flat()) {
this.facets.Keywords.push({id: x, name: "loading..."})
this.facets.Keywords.push({ id: x, name: "loading..." })
}
for (let x of this.search.search_books.map((x) => x.items).flat()) {
this.facets.Books.push({id: x, name: "loading..."})
this.facets.Books.push({ id: x, name: "loading..." })
}
this.loadMealPlan()
@ -1187,13 +1001,13 @@ export default {
"ui.expert_mode": function (newVal, oldVal) {
if (!newVal) {
this.search.search_keywords = this.search.search_keywords.map((x) => {
return {...x, not: false}
return { ...x, not: false }
})
this.search.search_foods = this.search.search_foods.map((x) => {
return {...x, not: false}
return { ...x, not: false }
})
this.search.search_books = this.search.search_books.map((x) => {
return {...x, not: false}
return { ...x, not: false }
})
}
},
@ -1263,13 +1077,13 @@ export default {
},
resetSearch: function (filter = undefined) {
this.search.search_keywords = this.search.search_keywords.map((x) => {
return {...x, items: []}
return { ...x, items: [] }
})
this.search.search_foods = this.search.search_foods.map((x) => {
return {...x, items: []}
return { ...x, items: [] }
})
this.search.search_books = this.search.search_books.map((x) => {
return {...x, items: []}
return { ...x, items: [] }
})
this.search.search_input = filter?.query ?? ""
this.search.search_internal = filter?.internal ?? false
@ -1324,28 +1138,27 @@ export default {
if (!this.ui.tree_select) {
return
}
let params = {hash: hash}
let params = { hash: hash }
if (facet) {
params[facet] = id
}
return this.genericGetAPI("api_get_facets", params).then((response) => {
this.facets = {...this.facets, ...response.data.facets}
this.facets = { ...this.facets, ...response.data.facets }
})
},
showSQL: function () {
let params = this.buildParams()
this.genericAPI(this.Models.RECIPE, this.Actions.LIST, params).then((result) => {
})
this.genericAPI(this.Models.RECIPE, this.Actions.LIST, params).then((result) => {})
},
// TODO refactor to combine with load KeywordChildren
loadFoodChildren({action, parentNode, callback}) {
loadFoodChildren({ action, parentNode, callback }) {
if (action === LOAD_CHILDREN_OPTIONS) {
if (this.facets?.cache_key) {
this.getFacets(this.facets.cache_key, "food", parentNode.id).then(callback())
}
}
},
loadKeywordChildren({action, parentNode, callback}) {
loadKeywordChildren({ action, parentNode, callback }) {
if (action === LOAD_CHILDREN_OPTIONS) {
if (this.facets?.cache_key) {
this.getFacets(this.facets.cache_key, "keyword", parentNode.id).then(callback())
@ -1356,7 +1169,7 @@ export default {
return
},
buildParams: function (random) {
let params = {options: {query: {}}, page: this.search.pagination_page, pageSize: this.ui.page_size}
let params = { options: { query: {} }, page: this.search.pagination_page, pageSize: this.ui.page_size }
if (this.search.search_filter) {
params.options.query.filter = this.search.search_filter.id
return params
@ -1473,10 +1286,12 @@ export default {
}
let search = this.buildParams(false)
console.log("after build", search)
;["page", "pageSize"].forEach((key) => {
delete search[key]
})
search = {...search, ...search.options.query}
search = { ...search, ...search.options.query }
console.log("after concat", search)
let params = {
name: filtername,
search: JSON.stringify(search),