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,10 +1,8 @@
<template>
<div id="app">
<h2>{{ $t('Export') }}</h2>
<h2>{{ $t("Export") }}</h2>
<div class="row">
<div class="col col-md-12">
<br />
<!-- TODO get option dynamicaly -->
<select class="form-control" v-model="recipe_app">
@ -16,7 +14,7 @@
<br />
<b-form-checkbox v-model="export_all" @change="disabled_multiselect = $event" name="check-button" switch style="margin-top: 1vh">
{{ $t('All recipes') }}
{{ $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>
<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 () {
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")
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'])
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

@ -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") }}
@ -717,8 +551,7 @@
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 />
</template>
@ -729,9 +562,7 @@
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 />
</template>
@ -742,9 +573,7 @@
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 />
</template>
@ -753,30 +582,24 @@
<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 />
</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
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 />
</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
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>
@ -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,30 +678,24 @@
<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>
@ -1334,8 +1148,7 @@ export default {
},
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 }) {
@ -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 }
console.log("after concat", search)
let params = {
name: filtername,
search: JSON.stringify(search),