Merge branch 'develop' of github.com:ndbeals/tandoor_recipes into develop

This commit is contained in:
Nathan Beals
2022-04-23 00:11:08 -04:00
31 changed files with 1312 additions and 698 deletions

View File

@@ -124,7 +124,7 @@ class IngredientParser:
def parse_amount(self, x): def parse_amount(self, x):
amount = 0 amount = 0
unit = '' unit = None
note = '' note = ''
did_check_frac = False did_check_frac = False
@@ -155,7 +155,7 @@ class IngredientParser:
except ValueError: except ValueError:
unit = x[end:] unit = x[end:]
if unit.startswith('(') or unit.startswith('-'): # i dont know any unit that starts with ( or - so its likely an alternative like 1L (500ml) Water or 2-3 if unit is not None and (unit.startswith('(') or unit.startswith('-')): # i dont know any unit that starts with ( or - so its likely an alternative like 1L (500ml) Water or 2-3
unit = '' unit = ''
note = x note = x
return amount, unit, note return amount, unit, note
@@ -230,7 +230,7 @@ class IngredientParser:
# a fraction for the amount # a fraction for the amount
if len(tokens) > 2: if len(tokens) > 2:
try: try:
if not unit == '': if unit is not None:
# a unit is already found, no need to try the second argument for a fraction # a unit is already found, no need to try the second argument for a fraction
# probably not the best method to do it, but I didn't want to make an if check and paste the exact same thing in the else as already is in the except # noqa: E501 # probably not the best method to do it, but I didn't want to make an if check and paste the exact same thing in the else as already is in the except # noqa: E501
raise ValueError raise ValueError
@@ -252,7 +252,7 @@ class IngredientParser:
# try to use second argument as unit and everything else as ingredient, use everything as ingredient if it fails # noqa: E501 # try to use second argument as unit and everything else as ingredient, use everything as ingredient if it fails # noqa: E501
try: try:
ingredient, note = self.parse_ingredient(tokens[2:]) ingredient, note = self.parse_ingredient(tokens[2:])
if unit == '': if unit is None:
unit = tokens[1] unit = tokens[1]
else: else:
note = tokens[1] note = tokens[1]

View File

@@ -10,33 +10,33 @@ def test_ingredient_parser():
"4 l Wasser": (4, "l", "Wasser", ""), "4 l Wasser": (4, "l", "Wasser", ""),
"½l Wasser": (0.5, "l", "Wasser", ""), "½l Wasser": (0.5, "l", "Wasser", ""),
"⅛ Liter Sauerrahm": (0.125, "Liter", "Sauerrahm", ""), "⅛ Liter Sauerrahm": (0.125, "Liter", "Sauerrahm", ""),
"5 Zwiebeln": (5, "", "Zwiebeln", ""), "5 Zwiebeln": (5, None, "Zwiebeln", ""),
"3 Zwiebeln, gehackt": (3, "", "Zwiebeln", "gehackt"), "3 Zwiebeln, gehackt": (3, None, "Zwiebeln", "gehackt"),
"5 Zwiebeln (gehackt)": (5, "", "Zwiebeln", "gehackt"), "5 Zwiebeln (gehackt)": (5, None, "Zwiebeln", "gehackt"),
"1 Zwiebel(n)": (1, "", "Zwiebel(n)", ""), "1 Zwiebel(n)": (1, None, "Zwiebel(n)", ""),
"4 1/2 Zwiebeln": (4.5, "", "Zwiebeln", ""), "4 1/2 Zwiebeln": (4.5, None, "Zwiebeln", ""),
"4 ½ Zwiebeln": (4.5, "", "Zwiebeln", ""), "4 ½ Zwiebeln": (4.5, None, "Zwiebeln", ""),
"1/2 EL Mehl": (0.5, "EL", "Mehl", ""), "1/2 EL Mehl": (0.5, "EL", "Mehl", ""),
"1/2 Zwiebel": (0.5, "", "Zwiebel", ""), "1/2 Zwiebel": (0.5, None, "Zwiebel", ""),
"1/5g Mehl, gesiebt": (0.2, "g", "Mehl", "gesiebt"), "1/5g Mehl, gesiebt": (0.2, "g", "Mehl", "gesiebt"),
"1/2 Zitrone, ausgepresst": (0.5, "", "Zitrone", "ausgepresst"), "1/2 Zitrone, ausgepresst": (0.5, None, "Zitrone", "ausgepresst"),
"etwas Mehl": (0, "", "etwas Mehl", ""), "etwas Mehl": (0, None, "etwas Mehl", ""),
"Öl zum Anbraten": (0, "", "Öl zum Anbraten", ""), "Öl zum Anbraten": (0, None, "Öl zum Anbraten", ""),
"n. B. Knoblauch, zerdrückt": (0, "", "n. B. Knoblauch", "zerdrückt"), "n. B. Knoblauch, zerdrückt": (0, None, "n. B. Knoblauch", "zerdrückt"),
"Kräuter, mediterrane (Oregano, Rosmarin, Basilikum)": ( "Kräuter, mediterrane (Oregano, Rosmarin, Basilikum)": (
0, "", "Kräuter, mediterrane", "Oregano, Rosmarin, Basilikum"), 0, None, "Kräuter, mediterrane", "Oregano, Rosmarin, Basilikum"),
"600 g Kürbisfleisch (Hokkaido), geschält, entkernt und geraspelt": ( "600 g Kürbisfleisch (Hokkaido), geschält, entkernt und geraspelt": (
600, "g", "Kürbisfleisch (Hokkaido)", "geschält, entkernt und geraspelt"), 600, "g", "Kürbisfleisch (Hokkaido)", "geschält, entkernt und geraspelt"),
"Muskat": (0, "", "Muskat", ""), "Muskat": (0, None, "Muskat", ""),
"200 g Mehl, glattes": (200, "g", "Mehl", "glattes"), "200 g Mehl, glattes": (200, "g", "Mehl", "glattes"),
"1 Ei(er)": (1, "", "Ei(er)", ""), "1 Ei(er)": (1, None, "Ei(er)", ""),
"1 Prise(n) Salz": (1, "Prise(n)", "Salz", ""), "1 Prise(n) Salz": (1, "Prise(n)", "Salz", ""),
"etwas Wasser, lauwarmes": (0, "", "etwas Wasser", "lauwarmes"), "etwas Wasser, lauwarmes": (0, None, "etwas Wasser", "lauwarmes"),
"Strudelblätter, fertige, für zwei Strudel": (0, "", "Strudelblätter", "fertige, für zwei Strudel"), "Strudelblätter, fertige, für zwei Strudel": (0,None, "Strudelblätter", "fertige, für zwei Strudel"),
"barrel-aged Bourbon": (0, "", "barrel-aged Bourbon", ""), "barrel-aged Bourbon": (0, None, "barrel-aged Bourbon", ""),
"golden syrup": (0, "", "golden syrup", ""), "golden syrup": (0, None, "golden syrup", ""),
"unsalted butter, for greasing": (0, "", "unsalted butter", "for greasing"), "unsalted butter, for greasing": (0, None, "unsalted butter", "for greasing"),
"unsalted butter , for greasing": (0, "", "unsalted butter", "for greasing"), # trim "unsalted butter , for greasing": (0, None, "unsalted butter", "for greasing"), # trim
"1 small sprig of fresh rosemary": (1, "small", "sprig of fresh rosemary", ""), "1 small sprig of fresh rosemary": (1, "small", "sprig of fresh rosemary", ""),
# does not always work perfectly! # does not always work perfectly!
"75 g fresh breadcrumbs": (75, "g", "fresh breadcrumbs", ""), "75 g fresh breadcrumbs": (75, "g", "fresh breadcrumbs", ""),
@@ -49,7 +49,7 @@ def test_ingredient_parser():
"1 Zwiebel gehackt": (1, "Zwiebel", "gehackt", ""), "1 Zwiebel gehackt": (1, "Zwiebel", "gehackt", ""),
"1 EL Kokosöl": (1, "EL", "Kokosöl", ""), "1 EL Kokosöl": (1, "EL", "Kokosöl", ""),
"0.5 paket jäst (à 50 g)": (0.5, "paket", "jäst", "à 50 g"), "0.5 paket jäst (à 50 g)": (0.5, "paket", "jäst", "à 50 g"),
"ägg": (0, "", "ägg", ""), "ägg": (0, None, "ägg", ""),
"50 g smör eller margarin": (50, "g", "smör eller margarin", ""), "50 g smör eller margarin": (50, "g", "smör eller margarin", ""),
"3,5 l Wasser": (3.5, "l", "Wasser", ""), "3,5 l Wasser": (3.5, "l", "Wasser", ""),
"3.5 l Wasser": (3.5, "l", "Wasser", ""), "3.5 l Wasser": (3.5, "l", "Wasser", ""),
@@ -70,4 +70,4 @@ def test_ingredient_parser():
for key, val in expectations.items(): for key, val in expectations.items():
count += 1 count += 1
parsed = ingredient_parser.parse(key) parsed = ingredient_parser.parse(key)
assert val == parsed assert parsed == val

View File

@@ -594,6 +594,7 @@ class IngredientViewSet(viewsets.ModelViewSet):
queryset = Ingredient.objects queryset = Ingredient.objects
serializer_class = IngredientSerializer serializer_class = IngredientSerializer
permission_classes = [CustomIsUser] permission_classes = [CustomIsUser]
pagination_class = DefaultPagination
def get_serializer_class(self): def get_serializer_class(self):
if self.request and self.request.query_params.get('simple', False): if self.request and self.request.query_params.get('simple', False):
@@ -1193,6 +1194,11 @@ def recipe_from_source(request):
'error': True, 'error': True,
'msg': _('Connection Refused.') 'msg': _('Connection Refused.')
}, status=400) }, status=400)
except requests.exceptions.MissingSchema:
return JsonResponse({
'error': True,
'msg': _('Bad URL Schema.')
}, status=400)
recipe_json, recipe_tree, recipe_html, recipe_images = get_recipe_from_source(data, url, request) recipe_json, recipe_tree, recipe_html, recipe_images = get_recipe_from_source(data, url, request)
if len(recipe_tree) == 0 and len(recipe_json) == 0: if len(recipe_tree) == 0 and len(recipe_json) == 0:
return JsonResponse({ return JsonResponse({

View File

@@ -58,3 +58,7 @@ apache:
I used two paths `<sub path>` and `<www path>` for simplicity. In my case I have `<sub path> = recipes` and `<www path> = serve/recipes`. One could also change the matching rules of traefik to have everything under one path. I used two paths `<sub path>` and `<www path>` for simplicity. In my case I have `<sub path> = recipes` and `<www path> = serve/recipes`. One could also change the matching rules of traefik to have everything under one path.
I left out the TLS config in this example for simplicity. I left out the TLS config in this example for simplicity.
## WSL
If you want to install Tandoor on the Windows Subsystem for Linux you can find a detailed post herre https://github.com/TandoorRecipes/recipes/issues/1733

View File

@@ -1,4 +1,4 @@
Django==3.2.12 Django==3.2.13
cryptography==36.0.2 cryptography==36.0.2
django-annoying==0.10.6 django-annoying==0.10.6
django-autocomplete-light==3.9.4 django-autocomplete-light==3.9.4

View File

@@ -130,10 +130,10 @@ export default {
.then((result) => { .then((result) => {
let new_book = result.data let new_book = result.data
this.refreshData() this.refreshData()
StandardToasts.makeStandardToast(StandardToasts.SUCCESS_CREATE) StandardToasts.makeStandardToast(this,StandardToasts.SUCCESS_CREATE)
}) })
.catch((error) => { .catch((err) => {
StandardToasts.makeStandardToast(StandardToasts.FAIL_CREATE) StandardToasts.makeStandardToast(this,StandardToasts.FAIL_CREATE, err)
}) })
}, },
appendRecipeFilter: function (page, book) { appendRecipeFilter: function (page, book) {

View File

@@ -117,8 +117,7 @@ export default {
this.recipe_list.push(response.data) this.recipe_list.push(response.data)
}) })
.catch((err) => { .catch((err) => {
console.log(err) StandardToasts.makeStandardToast(this,StandardToasts.FAIL_FETCH, err)
StandardToasts.makeStandardToast(StandardToasts.FAIL_FETCH)
}) })
// .then((e) => this.searchRecipes("")) // .then((e) => this.searchRecipes(""))
}, },
@@ -133,7 +132,7 @@ export default {
// }) // })
// .catch((err) => { // .catch((err) => {
// console.log(err) // console.log(err)
// StandardToasts.makeStandardToast(StandardToasts.FAIL_FETCH) // StandardToasts.makeStandardToast(this,StandardToasts.FAIL_FETCH)
// }) // })
// }, // },

View File

@@ -17,8 +17,10 @@
<b-card no-body> <b-card no-body>
<b-card-header header-tag="header" class="p-1" role="tab"> <b-card-header header-tag="header" class="p-1" role="tab">
<b-col cols="12" md="6" offset="0" offset-md="3"> <b-col cols="12" md="6" offset="0" offset-md="3">
<b-button block v-b-toggle.id_accordion_url variant="info">Website</b-button> <b-button block v-b-toggle.id_accordion_url variant="info">{{
<!-- TODO localize --> $t('Website')
}}
</b-button>
</b-col> </b-col>
</b-card-header> </b-card-header>
<b-collapse id="id_accordion_url" visible accordion="url_import_accordion" <b-collapse id="id_accordion_url" visible accordion="url_import_accordion"
@@ -30,7 +32,7 @@
<b-checkbox v-model="import_multiple" switch><span <b-checkbox v-model="import_multiple" switch><span
v-if="import_multiple">Multiple Recipes</span><span v-if="import_multiple">Multiple Recipes</span><span
v-if="!import_multiple">Single Recipe</span></b-checkbox> v-if="!import_multiple">Single Recipe</span></b-checkbox>
<!-- TODO localize --> <!-- TODO localize or maybe icons ? -->
</div> </div>
</div> </div>
<b-input-group class="mt-2" :class="{ bounce: empty_input }" <b-input-group class="mt-2" :class="{ bounce: empty_input }"
@@ -38,8 +40,7 @@
<b-input <b-input
class="form-control form-control-lg form-control-borderless form-control-search" class="form-control form-control-lg form-control-borderless form-control-search"
v-model="website_url" v-model="website_url"
placeholder="Website URL" @paste="onURLPaste"></b-input> placeholder="https://..." @paste="onURLPaste"></b-input>
<!-- TODO localize -->
<b-input-group-append> <b-input-group-append>
<b-button variant="primary" <b-button variant="primary"
@click="loadRecipe(website_url,false,undefined)"><i @click="loadRecipe(website_url,false,undefined)"><i
@@ -47,15 +48,15 @@
</b-button> </b-button>
</b-input-group-append> </b-input-group-append>
</b-input-group> </b-input-group>
<b-textarea rows="10" placeholder="Enter one URL per line" <b-textarea rows="10" :placeholder="$t('one_url_per_line')"
v-model="website_url_list" v-model="website_url_list"
v-if="import_multiple"> <!-- TODO localize --> v-if="import_multiple">
</b-textarea> </b-textarea>
<b-button class="float-right" v-if="import_multiple" <b-button class="float-right" v-if="import_multiple"
:disabled="website_url_list.length < 1" :disabled="website_url_list.length < 1"
@click="autoImport()">Import @click="autoImport()">{{ $t('Import') }}
</b-button> </b-button>
<div class="row mt-2"> <!-- TODO remove --> <div class="row mt-2"> <!-- TODO remove -->
<div class="col col-md-12"> <div class="col col-md-12">
@@ -89,7 +90,7 @@
<b-card-header header-tag="header" class="p-1" role="tab"> <b-card-header header-tag="header" class="p-1" role="tab">
<b-col cols="12" md="6" offset="0" offset-md="3"> <b-col cols="12" md="6" offset="0" offset-md="3">
<b-button block v-b-toggle.id_accordion_add_options variant="info" <b-button block v-b-toggle.id_accordion_add_options variant="info"
:disabled="recipe_json === undefined">Options :disabled="recipe_json === undefined">{{ $t('Options') }}
</b-button> </b-button>
</b-col> </b-col>
</b-card-header> </b-card-header>
@@ -127,9 +128,11 @@
<div class="row mt-1"> <div class="row mt-1">
<div class="col col-md-12 text-center"> <div class="col col-md-12 text-center">
<small class="text-muted">Click the image you want to import for this <small class="text-muted">{{ $t('click_image_import') }}</small><br/>
recipe</small> <!-- TODO localize --> <span
<span v-if="recipe_images.length === 0">No additional images found in source.</span> v-if="recipe_images.length === 0">{{
$t('no_more_images_found')
}}</span>
<div class="scrolling-wrapper-flexbox"> <div class="scrolling-wrapper-flexbox">
<div class="wrapper-card" v-for="i in recipe_images" <div class="wrapper-card" v-for="i in recipe_images"
v-bind:key="i" v-bind:key="i"
@@ -147,7 +150,7 @@
<b-card no-body> <b-card no-body>
<b-card-title> <b-card-title>
<div class="clearfix"> <div class="clearfix">
<span class="float-left h5">Keywords</span> <span class="float-left h5">{{ $t('Keywords') }}</span>
<b-button-group class="float-right"> <b-button-group class="float-right">
<b-button class="float-right" variant="primary" <b-button class="float-right" variant="primary"
@click="$set(recipe_json, 'keywords', recipe_json.keywords.map(x => {x.show = true; return x}))"> @click="$set(recipe_json, 'keywords', recipe_json.keywords.map(x => {x.show = true; return x}))">
@@ -194,7 +197,7 @@
<b-card-header header-tag="header" class="p-1" role="tab"> <b-card-header header-tag="header" class="p-1" role="tab">
<b-col cols="12" md="6" offset="0" offset-md="3"> <b-col cols="12" md="6" offset="0" offset-md="3">
<b-button block v-b-toggle.id_accordion_import variant="info" <b-button block v-b-toggle.id_accordion_import variant="info"
:disabled="recipe_json === undefined">Import :disabled="recipe_json === undefined">{{ $t('Import') }}
</b-button> </b-button>
</b-col> </b-col>
</b-card-header> </b-card-header>
@@ -261,31 +264,94 @@
</b-tab> </b-tab>
<!-- App Tab --> <!-- App Tab -->
<b-tab v-bind:title="$t('App')"> <b-tab v-bind:title="$t('App')">
<b-container>
<h4>{{ $t('Select_App_To_Import') }}:</h4>
<b-row class="mt-4">
<b-col cols="4" offset="0" offset-md="4" v-for="i in INTEGRATIONS_TD" :value="i.id"
v-bind:key="i.id">
<b-list-group style="max-width: 300px;">
<b-list-group-item class="d-flex align-items-center" v-hover
style="cursor: pointer"
v-bind:class="{ 'bg-success': recipe_app === i.id }"
@click="recipe_app = i.id">
<b-avatar class="mr-3"><i :class="i.icon"
v-if="i.img_src === undefined"></i><img
:src="i.img_src" v-if="i.img_src !== undefined" alt="Icon">
</b-avatar>
<span class="mr-auto">{{ i.name }}</span>
<b-badge variant="success" class="ml-1" v-b-tooltip:top
:title="$t('Import_Supported')"><i
class="fas fa-file-import fa-fw" v-if="i.import"></i></b-badge>
<b-badge variant="warning" class="ml-1" v-b-tooltip:top
:title="$t('Import_Not_Yet_Supported')"><i
class="fas fa-file-import fa-fw" v-if="!i.import"></i></b-badge>
<b-badge variant="success" class="ml-1" v-b-tooltip:top
:title="$t('Export_Supported')"><i
class="fas fa-file-export fa-fw" v-if="i.export"></i></b-badge>
<b-badge variant="warning" class="ml-1" v-b-tooltip:top
:title="$t('Export_Not_Yet_Supported')"><i
class="fas fa-file-export fa-fw" v-if="!i.export"></i></b-badge>
</b-list-group-item>
</b-list-group>
</b-col>
</b-row>
<b-row class="mt-4">
<b-col cols="3" v-for="i in INTEGRATIONS_WO" :value="i.id" v-bind:key="i.id"
class="mt-1">
<b-list-group style="max-width: 300px;">
<b-list-group-item class="d-flex align-items-center" v-hover
style="cursor: pointer"
v-bind:class="{ 'bg-success': recipe_app === i.id }"
@click="recipe_app = i.id">
<b-avatar class="mr-3"><i :class="i.icon"
v-if="i.img_src === undefined"></i><img
:src="i.img_src" v-if="i.img_src !== undefined" alt="Icon">
</b-avatar>
<span class="mr-auto">{{ i.name }}</span>
<b-badge variant="success" class="ml-1" v-b-tooltip:top
:title="$t('Import_Supported')"><i
class="fas fa-file-import fa-fw" v-if="i.import"></i></b-badge>
<b-badge variant="warning" class="ml-1" v-b-tooltip:top
:title="$t('Import_Not_Yet_Supported')"><i
class="fas fa-file-import fa-fw" v-if="!i.import"></i></b-badge>
<b-badge variant="success" class="ml-1" v-b-tooltip:top
:title="$t('Export_Supported')"><i
class="fas fa-file-export fa-fw" v-if="i.export"></i></b-badge>
<b-badge variant="warning" class="ml-1" v-b-tooltip:top
:title="$t('Export_Not_Yet_Supported')"><i
class="fas fa-file-export fa-fw" v-if="!i.export"></i></b-badge>
</b-list-group-item>
</b-list-group>
</b-col>
</b-row>
<b-row v-if="recipe_app_info !== undefined && recipe_app_info.help_url !== ''"
class="mt-3">
<b-col cols="12" class="text-center">
{{ $t('Importer_Help') }} <a
:href="recipe_app_info.help_url"> {{ $t('Documentation') }}</a>
</b-col>
</b-row>
<select class="form-control" v-model="recipe_app"> <b-form-checkbox v-model="import_duplicates" name="check-button" switch
<option v-for="i in INTEGRATIONS" :value="i.id" v-bind:key="i.id">{{ i.name }}</option> style="margin-top: 1vh">
</select> {{ $t('import_duplicates') }}
</b-form-checkbox>
<b-form-checkbox v-model="import_duplicates" name="check-button" switch
style="margin-top: 1vh">
{{ $t('import_duplicates') }}
</b-form-checkbox>
<a href="recipe_app_info.help_url" <b-form-file
v-if="recipe_app_info !== undefined && recipe_app_info.help_url !== ''">{{ class="my-2"
$t('Help') multiple
}}</a> size="lg"
v-model="recipe_files"
<b-form-file :placeholder="$t('Select_File')"
class="my-2" drop-placeholder="Drop recipe files here...">
multiple </b-form-file>
v-model="recipe_files" <div class="text-center">
:placeholder="$t('Select_File')" <b-button @click="importAppRecipe()" size="lg"
drop-placeholder="Drop recipe files here..."> id="id_btn_app"><i class="fas fa-file-archive"></i> {{ $t('Import') }}
</b-form-file> </b-button>
<button @click="importAppRecipe()" class="btn btn-primary shadow-none" type="button" </div>
id="id_btn_app"><i class="fas fa-file-archive"></i> {{ $t('Import') }} </b-container>
</button>
</b-tab> </b-tab>
<!-- Source Tab --> <!-- Source Tab -->
<b-tab v-bind:title="$t('Source')"> <b-tab v-bind:title="$t('Source')">
@@ -332,7 +398,15 @@ import {BootstrapVue} from 'bootstrap-vue'
import 'bootstrap-vue/dist/bootstrap-vue.css' import 'bootstrap-vue/dist/bootstrap-vue.css'
import {resolveDjangoStatic, resolveDjangoUrl, ResolveUrlMixin, StandardToasts, ToastMixin} from "@/utils/utils"; import {
RandomIconMixin,
resolveDjangoStatic,
resolveDjangoUrl,
ResolveUrlMixin,
StandardToasts,
ToastMixin
} from "@/utils/utils";
import axios from "axios"; import axios from "axios";
import {ApiApiFactory} from "@/utils/openapi/api"; import {ApiApiFactory} from "@/utils/openapi/api";
import {INTEGRATIONS} from "@/utils/integration"; import {INTEGRATIONS} from "@/utils/integration";
@@ -347,6 +421,7 @@ export default {
mixins: [ mixins: [
ResolveUrlMixin, ResolveUrlMixin,
ToastMixin, ToastMixin,
RandomIconMixin
], ],
components: { components: {
LoadingSpinner, LoadingSpinner,
@@ -357,10 +432,21 @@ export default {
recipe_app_info: function () { recipe_app_info: function () {
return this.INTEGRATIONS.filter(x => x.id === this.recipe_app)[0] return this.INTEGRATIONS.filter(x => x.id === this.recipe_app)[0]
}, },
INTEGRATIONS_WO: function () {
return this.INTEGRATIONS.filter((int) => {
return int.id !== "DEFAULT"
})
},
INTEGRATIONS_TD: function () {
return this.INTEGRATIONS.filter((int) => {
return int.id === "DEFAULT"
})
}
}, },
data() { data() {
return { return {
tab_index: 0, tab_index: 1,
collapse_visible: { collapse_visible: {
url: true, url: true,
options: false, options: false,
@@ -391,7 +477,8 @@ export default {
empty_input: false, empty_input: false,
edit_name: false, edit_name: false,
// Bookmarklet // Bookmarklet
BOOKMARKLET_CODE: window.BOOKMARKLET_CODE BOOKMARKLET_CODE: window.BOOKMARKLET_CODE,
error: undefined
} }
}, },
mounted() { mounted() {
@@ -402,6 +489,9 @@ export default {
if (window.BOOKMARKLET_IMPORT_ID !== -1) { if (window.BOOKMARKLET_IMPORT_ID !== -1) {
this.loadRecipe('', false, window.BOOKMARKLET_IMPORT_ID) this.loadRecipe('', false, window.BOOKMARKLET_IMPORT_ID)
} }
this.INTEGRATIONS.forEach((int) => {
int.icon = this.getRandomFoodIcon()
})
}, },
methods: { methods: {
/** /**
@@ -422,12 +512,12 @@ export default {
let recipe = response.data let recipe = response.data
apiFactory.imageRecipe(response.data.id, undefined, recipe_json.image).then(response => { // save recipe image apiFactory.imageRecipe(response.data.id, undefined, recipe_json.image).then(response => { // save recipe image
if (!silent) { if (!silent) {
StandardToasts.makeStandardToast(StandardToasts.SUCCESS_CREATE) StandardToasts.makeStandardToast(this, StandardToasts.SUCCESS_CREATE)
} }
this.afterImportAction(action, recipe) this.afterImportAction(action, recipe)
}).catch(e => { }).catch(e => {
if (!silent) { if (!silent) {
StandardToasts.makeStandardToast(StandardToasts.FAIL_UPDATE) StandardToasts.makeStandardToast(this, StandardToasts.FAIL_UPDATE)
} }
this.afterImportAction(action, recipe) this.afterImportAction(action, recipe)
}) })
@@ -436,13 +526,13 @@ export default {
this.failed_imports.push(recipe_json.source_url) this.failed_imports.push(recipe_json.source_url)
} }
if (!silent) { if (!silent) {
StandardToasts.makeStandardToast(StandardToasts.FAIL_CREATE) StandardToasts.makeStandardToast(this, StandardToasts.FAIL_CREATE)
} }
}) })
} else { } else {
console.log('cant import recipe without data') console.log('cant import recipe without data')
if (!silent) { if (!silent) {
StandardToasts.makeStandardToast(StandardToasts.FAIL_CREATE) StandardToasts.makeStandardToast(this, StandardToasts.FAIL_CREATE)
} }
} }
}, },
@@ -543,10 +633,11 @@ export default {
} }
return this.recipe_json return this.recipe_json
}).catch((err) => { }).catch((err) => {
this.loading = false
if (url !== '') { if (url !== '') {
this.failed_imports.push(url) this.failed_imports.push(url)
} }
StandardToasts.makeStandardToast(StandardToasts.FAIL_FETCH, err.response.data.msg) StandardToasts.makeStandardToast(this, StandardToasts.FAIL_FETCH, err)
throw "Load Recipe Error" throw "Load Recipe Error"
}) })
}, },
@@ -577,15 +668,14 @@ export default {
window.location.href = resolveDjangoUrl('view_import_response', response.data['import_id']) window.location.href = resolveDjangoUrl('view_import_response', response.data['import_id'])
}).catch((err) => { }).catch((err) => {
console.log(err) console.log(err)
StandardToasts.makeStandardToast(StandardToasts.FAIL_CREATE) StandardToasts.makeStandardToast(this, StandardToasts.FAIL_CREATE)
}) })
}, },
/** /**
* Handles pasting URLs * Handles pasting URLs
*/ */
onURLPaste: function (evt) { onURLPaste: function (evt) {
this.website_url = evt.clipboardData.getData('text') this.loadRecipe(evt.clipboardData.getData('text'), false, undefined)
this.loadRecipe(false, undefined)
return true; return true;
}, },
/**loadRecipe(false,undefined) /**loadRecipe(false,undefined)

View File

@@ -4,24 +4,31 @@
<div class="row mt-2"> <div class="row mt-2">
<div class="col col-md-6"> <div class="col col-md-6">
<generic-multiselect @change="food = $event.val; refreshList()" <generic-multiselect @change="food = $event.val; refreshList()" ref="food_multiselect"
:model="Models.FOOD" :model="Models.FOOD"
:initial_single_selection="food" :initial_single_selection="food"
:multiple="false"></generic-multiselect> :multiple="false"></generic-multiselect>
<b-button @click="show_food_delete=true" :disabled="food === null"><i class="fas fa-trash-alt"></i> <b-button @click="generic_model = Models.FOOD; generic_action=Actions.DELETE" :disabled="food === null">
<i class="fas fa-trash-alt"></i>
</b-button> </b-button>
<b-button @click="generic_model = Models.FOOD; generic_action=Actions.MERGE" :disabled="food === null"> <b-button @click="generic_model = Models.FOOD; generic_action=Actions.MERGE" :disabled="food === null">
<i class="fas fa-compress-arrows-alt"></i> <i class="fas fa-compress-arrows-alt"></i>
</b-button> </b-button>
<b-button @click="generic_model = Models.FOOD; generic_action=Actions.UPDATE" :disabled="food === null">
<i class="fas fa-edit"></i>
</b-button>
<generic-modal-form :model="Models.FOOD" :action="generic_action" :show="generic_model === Models.FOOD" <generic-modal-form :model="Models.FOOD" :action="generic_action" :show="generic_model === Models.FOOD"
:item1="food" :item1="food"
@finish-action="food = null; generic_action=null; generic_model=null"/> @finish-action="finishGenericAction"/>
</div> </div>
<div class="col col-md-6"> <div class="col col-md-6">
<generic-multiselect <generic-multiselect
@change="unit = $event.val; refreshList()" @change="unit = $event.val; refreshList()"
:model="Models.UNIT" :model="Models.UNIT"
ref="unit_multiselect"
:initial_single_selection="unit" :initial_single_selection="unit"
:multiple="false"></generic-multiselect> :multiple="false"></generic-multiselect>
@@ -31,14 +38,20 @@
<b-button @click="generic_model = Models.UNIT; generic_action=Actions.MERGE" :disabled="unit === null"> <b-button @click="generic_model = Models.UNIT; generic_action=Actions.MERGE" :disabled="unit === null">
<i class="fas fa-compress-arrows-alt"></i> <i class="fas fa-compress-arrows-alt"></i>
</b-button> </b-button>
<b-button @click="generic_model = Models.UNIT; generic_action=Actions.UPDATE" :disabled="unit === null">
<i class="fas fa-edit"></i>
</b-button>
<generic-modal-form :model="Models.UNIT" :action="generic_action" :show="generic_model === Models.UNIT" <generic-modal-form :model="Models.UNIT" :action="generic_action" :show="generic_model === Models.UNIT"
:item1="unit" :item1="unit"
@finish-action="unit = null; generic_action=null; generic_model=null"/> @finish-action="finishGenericAction()"/>
</div> </div>
</div> </div>
<b-pagination pills v-model="current_page" :total-rows="total_object_count" :per-page="page_size"
@change="pageChange"></b-pagination>
<div class="row mt-2"> <div class="row mt-2">
<div class="col col-md-12"> <div class="col col-md-12">
<table class="table table-bordered"> <table class="table table-bordered">
@@ -100,7 +113,7 @@
@click="updateIngredient(i)"> @click="updateIngredient(i)">
<i class="fas fa-save"></i> <i class="fas fa-save"></i>
</b-button> </b-button>
<b-button variant="danger" <b-button variant="danger"
@click="deleteIngredient(i)"> @click="deleteIngredient(i)">
<i class="fas fa-trash"></i> <i class="fas fa-trash"></i>
</b-button> </b-button>
@@ -113,6 +126,9 @@
</template> </template>
</table> </table>
<b-pagination pills v-model="current_page" :total-rows="total_object_count" :per-page="page_size"
@change="pageChange"></b-pagination>
</div> </div>
</div> </div>
@@ -148,6 +164,9 @@ export default {
generic_model: null, generic_model: null,
show_food_delete: false, show_food_delete: false,
show_unit_delete: false, show_unit_delete: false,
current_page: 1,
total_object_count: 0,
page_size: 50,
} }
}, },
computed: {}, computed: {},
@@ -176,22 +195,27 @@ export default {
} else { } else {
this.loading = true this.loading = true
let apiClient = new ApiApiFactory() let apiClient = new ApiApiFactory()
let params = {'query': {'simple': 1}} let params = {'query': {'simple': 1,}}
if (this.food !== null) { if (this.food !== null) {
params.query.food = this.food.id params.query.food = this.food.id
} }
if (this.unit !== null) { if (this.unit !== null) {
params.query.unit = this.unit.id params.query.unit = this.unit.id
} }
apiClient.listIngredients(params).then(result => { apiClient.listIngredients(this.current_page, this.page_size,params).then(result => {
this.ingredients = result.data this.ingredients = result.data.results
this.total_object_count = result.data.count
this.loading = false this.loading = false
}).catch((err) => { }).catch((err) => {
StandardToasts.makeStandardToast(StandardToasts.FAIL_FETCH) StandardToasts.makeStandardToast(this, StandardToasts.FAIL_FETCH, err)
this.loading = false this.loading = false
}) })
} }
}, },
pageChange: function (page) {
this.current_page = page
this.refreshList()
},
updateIngredient: function (i) { updateIngredient: function (i) {
let update_list = [] let update_list = []
if (i === undefined) { if (i === undefined) {
@@ -208,21 +232,79 @@ export default {
let apiClient = new ApiApiFactory() let apiClient = new ApiApiFactory()
apiClient.updateIngredient(i.id, i).then(r => { apiClient.updateIngredient(i.id, i).then(r => {
this.$set(i, 'changed', false) this.$set(i, 'changed', false)
}).catch((r, e) => { }).catch(err => {
StandardToasts.makeStandardToast(StandardToasts.FAIL_UPDATE) StandardToasts.makeStandardToast(this, StandardToasts.FAIL_UPDATE, err)
}) })
}) })
}, },
deleteIngredient: function (i){ deleteIngredient: function (i) {
if (confirm(this.$t('delete_confirmation', this.$t('Ingredient')))){ if (confirm(this.$t('delete_confirmation', this.$t('Ingredient')))) {
let apiClient = new ApiApiFactory() let apiClient = new ApiApiFactory()
apiClient.destroyIngredient(i.id).then(r => { apiClient.destroyIngredient(i.id).then(r => {
StandardToasts.makeStandardToast(StandardToasts.SUCCESS_DELETE) StandardToasts.makeStandardToast(this, StandardToasts.SUCCESS_DELETE)
this.ingredients = this.ingredients.filter(li => li.id !== i.id) this.ingredients = this.ingredients.filter(li => li.id !== i.id)
}).catch(e => { }).catch(err => {
StandardToasts.makeStandardToast(StandardToasts.FAIL_DELETE) StandardToasts.makeStandardToast(this, StandardToasts.FAIL_DELETE, err)
}) })
} }
},
finishGenericAction: function (e) {
if (e !== 'cancel') {
if (this.generic_action === this.Actions.DELETE) {
this.ingredients = []
if (this.generic_model === this.Models.FOOD) {
this.food = null;
} else {
this.unit = null;
}
}
if (this.generic_action === this.Actions.UPDATE) {
if (this.generic_model === this.Models.FOOD) {
this.food = e.item
this.ingredients.forEach((element, i) => {
if (element.food.id === this.food.id) {
this.ingredients[i].food = this.food
}
})
} else {
this.unit = e.item
this.ingredients.forEach((element, i) => {
if (element.unit?.id === this.unit.id) {
this.ingredients[i].unit = this.unit
}
})
}
}
if (this.generic_action === this.Actions.MERGE) {
if (this.generic_model === this.Models.FOOD) {
this.ingredients.forEach((element, i) => {
if (element.food.id === this.food.id) {
this.ingredients[i].food = e.target_object
}
})
this.food = e.target_object
} else {
this.ingredients.forEach((element, i) => {
if (element.unit?.id === this.unit.id) {
this.ingredients[i].unit = e.target_object
}
})
this.unit = e.target_object
}
this.refreshList()
}
}
if (this.generic_model === this.Models.FOOD) {
this.$refs.food_multiselect.search('');
} else {
this.$refs.unit_multiselect.search('');
}
this.generic_action = null;
this.generic_model = null;
} }
}, },

View File

@@ -2,7 +2,7 @@
<div> <div>
<b-tabs content-class="mt-3" v-model="current_tab"> <b-tabs content-class="mt-3" v-model="current_tab">
<b-tab :title="$t('Planner')" active> <b-tab :title="$t('Planner')" active>
<div class="row"> <div class="row calender-row">
<div class="col-12 calender-parent"> <div class="col-12 calender-parent">
<calendar-view <calendar-view
:show-date="showDate" :show-date="showDate"
@@ -450,8 +450,8 @@ export default {
.then((e) => { .then((e) => {
this.periodChangedCallback(this.current_period) this.periodChangedCallback(this.current_period)
}) })
.catch((error) => { .catch((err) => {
StandardToasts.makeStandardToast(StandardToasts.FAIL_UPDATE) StandardToasts.makeStandardToast(this,StandardToasts.FAIL_UPDATE, err)
}) })
this.refreshMealTypes() this.refreshMealTypes()
@@ -473,8 +473,8 @@ export default {
updated++ updated++
} }
}) })
.catch((error) => { .catch((err) => {
StandardToasts.makeStandardToast(StandardToasts.FAIL_UPDATE) StandardToasts.makeStandardToast(this,StandardToasts.FAIL_UPDATE, err)
}) })
}) })
}, },
@@ -488,10 +488,10 @@ export default {
.updateMealType(this.meal_types[index].id, this.meal_types[index]) .updateMealType(this.meal_types[index].id, this.meal_types[index])
.then((e) => { .then((e) => {
this.periodChangedCallback(this.current_period) this.periodChangedCallback(this.current_period)
StandardToasts.makeStandardToast(StandardToasts.SUCCESS_UPDATE) StandardToasts.makeStandardToast(this,StandardToasts.SUCCESS_UPDATE)
}) })
.catch((error) => { .catch((err) => {
StandardToasts.makeStandardToast(StandardToasts.FAIL_UPDATE) StandardToasts.makeStandardToast(this,StandardToasts.FAIL_UPDATE, err)
}) })
} else { } else {
this.$set(this.meal_types[index], "editing", true) this.$set(this.meal_types[index], "editing", true)
@@ -504,10 +504,10 @@ export default {
.destroyMealType(this.meal_types[index].id) .destroyMealType(this.meal_types[index].id)
.then((e) => { .then((e) => {
this.periodChangedCallback(this.current_period) this.periodChangedCallback(this.current_period)
StandardToasts.makeStandardToast(StandardToasts.SUCCESS_DELETE) StandardToasts.makeStandardToast(this,StandardToasts.SUCCESS_DELETE)
}) })
.catch((error) => { .catch((err) => {
StandardToasts.makeStandardToast(StandardToasts.FAIL_DELETE) StandardToasts.makeStandardToast(this,StandardToasts.FAIL_DELETE, err)
}) })
}, },
updateEmoji: function (field, value) { updateEmoji: function (field, value) {
@@ -582,8 +582,8 @@ export default {
.then((e) => { .then((e) => {
list.splice(index, 1) list.splice(index, 1)
}) })
.catch((error) => { .catch((err) => {
StandardToasts.makeStandardToast(StandardToasts.FAIL_UPDATE) StandardToasts.makeStandardToast(this,StandardToasts.FAIL_UPDATE, err)
}) })
} }
}) })
@@ -634,8 +634,8 @@ export default {
let apiClient = new ApiApiFactory() let apiClient = new ApiApiFactory()
apiClient.updateMealPlan(entry.id, entry).catch((error) => { apiClient.updateMealPlan(entry.id, entry).catch((err) => {
StandardToasts.makeStandardToast(StandardToasts.FAIL_UPDATE) StandardToasts.makeStandardToast(this,StandardToasts.FAIL_UPDATE, err)
}) })
}, },
createEntry(entry) { createEntry(entry) {
@@ -645,8 +645,8 @@ export default {
apiClient apiClient
.createMealPlan(entry) .createMealPlan(entry)
.catch((error) => { .catch((err) => {
StandardToasts.makeStandardToast(StandardToasts.FAIL_UPDATE) StandardToasts.makeStandardToast(this,StandardToasts.FAIL_UPDATE, err)
}) })
.then((entry_result) => { .then((entry_result) => {
this.plan_entries.push(entry_result.data) this.plan_entries.push(entry_result.data)
@@ -693,19 +693,24 @@ export default {
opacity: 0; opacity: 0;
} }
.calender-row {
height: calc(100% - 240px);
}
.calender-parent { .calender-parent {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
flex-grow: 1; flex-grow: 1;
overflow-x: hidden; overflow-x: hidden;
overflow-y: hidden; overflow-y: hidden;
height: 70vh; height: 100%
} }
.cv-item { .cv-item {
white-space: inherit !important; white-space: inherit !important;
} }
.isHovered { .isHovered {
box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15) !important; box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15) !important;
} }
@@ -837,4 +842,10 @@ having to override as much.
opacity: 0.5; opacity: 0.5;
background: #c8ebfb; background: #c8ebfb;
} }
@media (max-width: 767.9px) {
.periodLabel {
font-size: 18px !important;
}
}
</style> </style>

View File

@@ -275,8 +275,7 @@ export default {
} }
}) })
.catch((err) => { .catch((err) => {
console.log(err, Object.keys(err)) StandardToasts.makeStandardToast(this,StandardToasts.FAIL_FETCH, err)
StandardToasts.makeStandardToast(StandardToasts.FAIL_FETCH)
}) })
}, },
getThis: function (id, callback) { getThis: function (id, callback) {
@@ -292,21 +291,19 @@ export default {
this.items_left = [result.data].concat(this.destroyCard(result?.data?.id, this.items_left)) this.items_left = [result.data].concat(this.destroyCard(result?.data?.id, this.items_left))
// this creates a deep copy to make sure that columns stay independent // this creates a deep copy to make sure that columns stay independent
this.items_right = [{...result.data}].concat(this.destroyCard(result?.data?.id, this.items_right)) this.items_right = [{...result.data}].concat(this.destroyCard(result?.data?.id, this.items_right))
StandardToasts.makeStandardToast(StandardToasts.SUCCESS_CREATE) StandardToasts.makeStandardToast(this,StandardToasts.SUCCESS_CREATE)
}) })
.catch((err) => { .catch((err) => {
console.log(err) StandardToasts.makeStandardToast(this,StandardToasts.FAIL_CREATE, err)
StandardToasts.makeStandardToast(StandardToasts.FAIL_CREATE)
}) })
} else { } else {
this.genericAPI(this.this_model, this.Actions.UPDATE, item) this.genericAPI(this.this_model, this.Actions.UPDATE, item)
.then((result) => { .then((result) => {
this.refreshThis(item.id) this.refreshThis(item.id)
StandardToasts.makeStandardToast(StandardToasts.SUCCESS_UPDATE) StandardToasts.makeStandardToast(this,StandardToasts.SUCCESS_UPDATE)
}) })
.catch((err) => { .catch((err) => {
console.log(err, err.response) StandardToasts.makeStandardToast(this,StandardToasts.FAIL_UPDATE, err)
StandardToasts.makeStandardToast(StandardToasts.FAIL_UPDATE)
}) })
} }
}, },
@@ -315,7 +312,7 @@ export default {
let api = new ApiApiFactory() let api = new ApiApiFactory()
food.shopping = true food.shopping = true
api.createShoppingListEntry({food: food, amount: 1}).then(() => { api.createShoppingListEntry({food: food, amount: 1}).then(() => {
StandardToasts.makeStandardToast(StandardToasts.SUCCESS_CREATE) StandardToasts.makeStandardToast(this,StandardToasts.SUCCESS_CREATE)
this.refreshCard(food, this.items_left) this.refreshCard(food, this.items_left)
this.refreshCard({...food}, this.items_right) this.refreshCard({...food}, this.items_right)
}) })
@@ -339,7 +336,7 @@ export default {
this.genericAPI(this.this_model, this.Actions.MOVE, {source: source_id, target: target_id}) this.genericAPI(this.this_model, this.Actions.MOVE, {source: source_id, target: target_id})
.then((result) => { .then((result) => {
this.moveUpdateItem(source_id, target_id) this.moveUpdateItem(source_id, target_id)
StandardToasts.makeStandardToast(StandardToasts.SUCCESS_MOVE) StandardToasts.makeStandardToast(this,StandardToasts.SUCCESS_MOVE)
}) })
.catch((err) => { .catch((err) => {
console.log(err) console.log(err)
@@ -378,7 +375,7 @@ export default {
}) })
.then((result) => { .then((result) => {
this.mergeUpdateItem(source_id, target_id) this.mergeUpdateItem(source_id, target_id)
StandardToasts.makeStandardToast(StandardToasts.SUCCESS_MERGE) StandardToasts.makeStandardToast(this,StandardToasts.SUCCESS_MERGE)
}) })
.catch((err) => { .catch((err) => {
//TODO error checking not working with OpenAPI methods //TODO error checking not working with OpenAPI methods
@@ -432,7 +429,7 @@ export default {
}) })
.catch((err) => { .catch((err) => {
console.log(err) console.log(err)
StandardToasts.makeStandardToast(StandardToasts.FAIL_FETCH) StandardToasts.makeStandardToast(this,StandardToasts.FAIL_FETCH, err)
}) })
}, },
getRecipes: function (col, item) { getRecipes: function (col, item) {

View File

@@ -821,8 +821,7 @@ export default {
}) })
.catch((err) => { .catch((err) => {
this.loading = false this.loading = false
console.log(err) StandardToasts.makeStandardToast(this,StandardToasts.FAIL_FETCH, err)
StandardToasts.makeStandardToast(StandardToasts.FAIL_FETCH)
}) })
}, },
updateRecipe: function (view_after) { updateRecipe: function (view_after) {
@@ -850,7 +849,7 @@ export default {
apiFactory apiFactory
.updateRecipe(this.recipe_id, this.recipe, {}) .updateRecipe(this.recipe_id, this.recipe, {})
.then((response) => { .then((response) => {
StandardToasts.makeStandardToast(StandardToasts.SUCCESS_UPDATE) StandardToasts.makeStandardToast(this,StandardToasts.SUCCESS_UPDATE)
this.recipe_changed = false this.recipe_changed = false
if (this.create_food) { if (this.create_food) {
apiFactory.createFood({ apiFactory.createFood({
@@ -863,8 +862,7 @@ export default {
} }
}) })
.catch((err) => { .catch((err) => {
console.log(err) StandardToasts.makeStandardToast(this,StandardToasts.FAIL_UPDATE, err)
StandardToasts.makeStandardToast(StandardToasts.FAIL_UPDATE)
}) })
}, },
uploadImage: function (file) { uploadImage: function (file) {
@@ -875,11 +873,10 @@ export default {
.then((request) => { .then((request) => {
this.recipe.image = request.data.image this.recipe.image = request.data.image
this.recipe_changed = false this.recipe_changed = false
StandardToasts.makeStandardToast(StandardToasts.SUCCESS_UPDATE) StandardToasts.makeStandardToast(this,StandardToasts.SUCCESS_UPDATE)
}) })
.catch((err) => { .catch((err) => {
StandardToasts.makeStandardToast(StandardToasts.FAIL_UPDATE) StandardToasts.makeStandardToast(this,StandardToasts.FAIL_UPDATE, err)
console.log(err.request, err.response)
}) })
} }
}, },
@@ -891,11 +888,10 @@ export default {
.then((request) => { .then((request) => {
this.recipe.image = null this.recipe.image = null
this.recipe_changed = false this.recipe_changed = false
StandardToasts.makeStandardToast(StandardToasts.SUCCESS_DELETE) StandardToasts.makeStandardToast(this,StandardToasts.SUCCESS_DELETE)
}) })
.catch((err) => { .catch((err) => {
StandardToasts.makeStandardToast(StandardToasts.FAIL_DELETE) StandardToasts.makeStandardToast(this,StandardToasts.FAIL_DELETE, err)
console.log(err.request, err.response)
}) })
} }
}, },
@@ -990,8 +986,7 @@ export default {
this.keywords_loading = false this.keywords_loading = false
}) })
.catch((err) => { .catch((err) => {
console.log(err) StandardToasts.makeStandardToast(this,StandardToasts.FAIL_FETCH, err)
StandardToasts.makeStandardToast(StandardToasts.FAIL_FETCH)
}) })
}, },
searchFiles: function (query) { searchFiles: function (query) {
@@ -1005,8 +1000,7 @@ export default {
this.files_loading = false this.files_loading = false
}) })
.catch((err) => { .catch((err) => {
console.log(err) StandardToasts.makeStandardToast(this,StandardToasts.FAIL_FETCH, err)
StandardToasts.makeStandardToast(StandardToasts.FAIL_FETCH)
}) })
}, },
searchRecipes: function (query) { searchRecipes: function (query) {
@@ -1017,8 +1011,7 @@ export default {
this.recipes_loading = false this.recipes_loading = false
}) })
.catch((err) => { .catch((err) => {
console.log(err) StandardToasts.makeStandardToast(this,StandardToasts.FAIL_FETCH, err)
StandardToasts.makeStandardToast(StandardToasts.FAIL_FETCH)
}) })
}, },
searchUnits: function (query) { searchUnits: function (query) {
@@ -1042,7 +1035,7 @@ export default {
this.units_loading = false this.units_loading = false
}) })
.catch((err) => { .catch((err) => {
StandardToasts.makeStandardToast(StandardToasts.FAIL_FETCH) StandardToasts.makeStandardToast(this,StandardToasts.FAIL_FETCH, err)
}) })
}, },
searchFoods: function (query) { searchFoods: function (query) {
@@ -1067,7 +1060,7 @@ export default {
this.foods_loading = false this.foods_loading = false
}) })
.catch((err) => { .catch((err) => {
StandardToasts.makeStandardToast(StandardToasts.FAIL_FETCH) StandardToasts.makeStandardToast(this,StandardToasts.FAIL_FETCH, err)
}) })
}, },
fileCreated: function (data) { fileCreated: function (data) {

View File

@@ -1496,11 +1496,10 @@ export default {
this.genericAPI(this.Models.CUSTOM_FILTER, this.Actions.CREATE, params) this.genericAPI(this.Models.CUSTOM_FILTER, this.Actions.CREATE, params)
.then((result) => { .then((result) => {
this.search.search_filter = result.data this.search.search_filter = result.data
StandardToasts.makeStandardToast(StandardToasts.SUCCESS_CREATE) StandardToasts.makeStandardToast(this,StandardToasts.SUCCESS_CREATE)
}) })
.catch((err) => { .catch((err) => {
console.log(err, Object.keys(err)) StandardToasts.makeStandardToast(this,StandardToasts.FAIL_CREATE, err)
StandardToasts.makeStandardToast(StandardToasts.FAIL_CREATE)
}) })
}, },
addField: function (field, count) { addField: function (field, count) {

View File

@@ -233,7 +233,7 @@ export default {
this.loadRecipe(window.RECIPE_ID) this.loadRecipe(window.RECIPE_ID)
this.$i18n.locale = window.CUSTOM_LOCALE this.$i18n.locale = window.CUSTOM_LOCALE
this.requestWakeLock() this.requestWakeLock()
window.addEventListener('resize', this.handleRezise); window.addEventListener('resize', this.handleResize);
}, },
beforeUnmount() { beforeUnmount() {
this.destroyWakeLock() this.destroyWakeLock()
@@ -249,7 +249,7 @@ export default {
} }
} }
}, },
handleRezise: function () { handleResize: function () {
if (document.getElementById('nutrition_container') !== null) { if (document.getElementById('nutrition_container') !== null) {
this.ingredient_height = document.getElementById('ingredient_container').clientHeight - document.getElementById('nutrition_container').clientHeight this.ingredient_height = document.getElementById('ingredient_container').clientHeight - document.getElementById('nutrition_container').clientHeight
} else { } else {
@@ -300,7 +300,7 @@ export default {
this.loading = false this.loading = false
setTimeout(() => { setTimeout(() => {
this.handleRezise() this.handleResize()
}, 100) }, 100)
}) })
}, },

File diff suppressed because it is too large Load Diff

View File

@@ -87,21 +87,21 @@ export default {
apiFactory.createRecipeBook({ name: name }).then((r) => { apiFactory.createRecipeBook({ name: name }).then((r) => {
this.books.push(r.data) this.books.push(r.data)
this.selected_book = r.data this.selected_book = r.data
StandardToasts.makeStandardToast(StandardToasts.SUCCESS_CREATE) StandardToasts.makeStandardToast(this,StandardToasts.SUCCESS_CREATE)
}) })
}, },
addToBook: function () { addToBook: function () {
let apiFactory = new ApiApiFactory() let apiFactory = new ApiApiFactory()
apiFactory.createRecipeBookEntry({ book: this.selected_book.id, recipe: this.recipe.id }).then((r) => { apiFactory.createRecipeBookEntry({ book: this.selected_book.id, recipe: this.recipe.id }).then((r) => {
this.recipe_book_list.push(r.data) this.recipe_book_list.push(r.data)
StandardToasts.makeStandardToast(StandardToasts.SUCCESS_CREATE) StandardToasts.makeStandardToast(this,StandardToasts.SUCCESS_CREATE)
}) })
}, },
removeFromBook: function (book_entry) { removeFromBook: function (book_entry) {
let apiFactory = new ApiApiFactory() let apiFactory = new ApiApiFactory()
apiFactory.destroyRecipeBookEntry(book_entry.id).then((r) => { apiFactory.destroyRecipeBookEntry(book_entry.id).then((r) => {
this.recipe_book_list = this.recipe_book_list.filter((e) => e.id !== book_entry.id) this.recipe_book_list = this.recipe_book_list.filter((e) => e.id !== book_entry.id)
StandardToasts.makeStandardToast(StandardToasts.SUCCESS_DELETE) StandardToasts.makeStandardToast(this,StandardToasts.SUCCESS_DELETE)
}) })
}, },
loadBookEntries: function () { loadBookEntries: function () {

View File

@@ -66,7 +66,7 @@ export default {
} }
this.genericAPI(this.Models.FOOD, this.Actions.SHOPPING, params).then((result) => { this.genericAPI(this.Models.FOOD, this.Actions.SHOPPING, params).then((result) => {
this.shopping = true this.shopping = true
StandardToasts.makeStandardToast(StandardToasts.SUCCESS_CREATE) StandardToasts.makeStandardToast(this,StandardToasts.SUCCESS_CREATE)
}) })
}, },
cancelDelete() { cancelDelete() {
@@ -80,7 +80,7 @@ export default {
this.genericAPI(this.Models.FOOD, this.Actions.SHOPPING, params).then(() => { this.genericAPI(this.Models.FOOD, this.Actions.SHOPPING, params).then(() => {
this.shopping = false this.shopping = false
this.$refs["shopping" + this.item.id].$emit("close") this.$refs["shopping" + this.item.id].$emit("close")
StandardToasts.makeStandardToast(StandardToasts.SUCCESS_DELETE) StandardToasts.makeStandardToast(this,StandardToasts.SUCCESS_DELETE)
}) })
}, },
}, },

View File

@@ -114,10 +114,10 @@ export default {
apiClient apiClient
.updateRecipeBook(this.book_copy.id, this.book_copy) .updateRecipeBook(this.book_copy.id, this.book_copy)
.then((result) => { .then((result) => {
StandardToasts.makeStandardToast(StandardToasts.SUCCESS_UPDATE) StandardToasts.makeStandardToast(this,StandardToasts.SUCCESS_UPDATE)
}) })
.catch((error) => { .catch((err) => {
StandardToasts.makeStandardToast(StandardToasts.FAIL_UPDATE) StandardToasts.makeStandardToast(this,StandardToasts.FAIL_UPDATE, err)
}) })
}, },
refreshData: function () { refreshData: function () {
@@ -135,10 +135,10 @@ export default {
.destroyRecipeBook(this.book.id) .destroyRecipeBook(this.book.id)
.then((result) => { .then((result) => {
this.$emit("refresh") this.$emit("refresh")
StandardToasts.makeStandardToast(StandardToasts.SUCCESS_DELETE) StandardToasts.makeStandardToast(this,StandardToasts.SUCCESS_DELETE)
}) })
.catch((error) => { .catch((err) => {
StandardToasts.makeStandardToast(StandardToasts.FAIL_DELETE) StandardToasts.makeStandardToast(this,StandardToasts.FAIL_DELETE, err)
}) })
} }
}, },

View File

@@ -140,7 +140,7 @@ export default {
}, },
nothingSelected() { nothingSelected() {
if (this.multiple || !this.initial_single_selection) { if (this.multiple || !this.initial_single_selection) {
return this.selected_objects.length === 0 && this.initial_selection.length === 0 return this.selected_objects?.length === 0 && this.initial_selection?.length === 0
} else { } else {
return !this.selected_objects && !this.initial_single_selection return !this.selected_objects && !this.initial_single_selection
} }
@@ -187,7 +187,7 @@ export default {
console.log('CREATEING NEW with -> ' , e) console.log('CREATEING NEW with -> ' , e)
this.genericAPI(this.model, this.Actions.CREATE, {name: e}).then(result => { this.genericAPI(this.model, this.Actions.CREATE, {name: e}).then(result => {
let createdObj = result.data?.results ?? result.data let createdObj = result.data?.results ?? result.data
StandardToasts.makeStandardToast(StandardToasts.SUCCESS_CREATE) StandardToasts.makeStandardToast(this,StandardToasts.SUCCESS_CREATE)
if (this.multiple) { if (this.multiple) {
this.selected_objects.push(createdObj) this.selected_objects.push(createdObj)
} else { } else {
@@ -196,7 +196,7 @@ export default {
this.objects.push(createdObj) this.objects.push(createdObj)
this.selectionChanged() this.selectionChanged()
}).catch((r, err) => { }).catch((r, err) => {
StandardToasts.makeStandardToast(StandardToasts.FAIL_CREATE) StandardToasts.makeStandardToast(this,StandardToasts.FAIL_CREATE)
}) })
}, },
}, },

View File

@@ -175,20 +175,20 @@ export default {
this.genericAPI(this.Models.RECIPE, this.Actions.SHOPPING, params) this.genericAPI(this.Models.RECIPE, this.Actions.SHOPPING, params)
.then((result) => { .then((result) => {
if (del_shopping) { if (del_shopping) {
StandardToasts.makeStandardToast(StandardToasts.SUCCESS_DELETE) StandardToasts.makeStandardToast(this,StandardToasts.SUCCESS_DELETE)
} else if (this.selected_shoppingrecipe) { } else if (this.selected_shoppingrecipe) {
StandardToasts.makeStandardToast(StandardToasts.SUCCESS_UPDATE) StandardToasts.makeStandardToast(this,StandardToasts.SUCCESS_UPDATE)
} else { } else {
StandardToasts.makeStandardToast(StandardToasts.SUCCESS_CREATE) StandardToasts.makeStandardToast(this,StandardToasts.SUCCESS_CREATE)
} }
}) })
.catch((err) => { .catch((err) => {
if (del_shopping) { if (del_shopping) {
StandardToasts.makeStandardToast(StandardToasts.FAIL_DELETE) StandardToasts.makeStandardToast(this,StandardToasts.FAIL_DELETE, err)
} else if (this.selected_shoppingrecipe) { } else if (this.selected_shoppingrecipe) {
StandardToasts.makeStandardToast(StandardToasts.FAIL_UPDATE) StandardToasts.makeStandardToast(this,StandardToasts.FAIL_UPDATE, err)
} else { } else {
StandardToasts.makeStandardToast(StandardToasts.FAIL_CREATE) StandardToasts.makeStandardToast(this,StandardToasts.FAIL_CREATE, err)
} }
this.$emit("shopping-failed") this.$emit("shopping-failed")
}) })

View File

@@ -127,4 +127,10 @@ export default {
.meal-plan-card { .meal-plan-card {
background-color: #fff; background-color: #fff;
} }
@media (max-width: 767.9px) {
.meal-plan-card {
font-size: 13px;
}
}
</style> </style>

View File

@@ -90,23 +90,23 @@ export default {
apiFactory.createRecipeBook({name: name}).then(r => { apiFactory.createRecipeBook({name: name}).then(r => {
this.books.push(r.data) this.books.push(r.data)
this.selected_book = r.data this.selected_book = r.data
StandardToasts.makeStandardToast(StandardToasts.SUCCESS_CREATE) StandardToasts.makeStandardToast(this,StandardToasts.SUCCESS_CREATE)
}) })
}, },
addToBook: function () { addToBook: function () {
let apiFactory = new ApiApiFactory() let apiFactory = new ApiApiFactory()
apiFactory.createRecipeBookEntry({book: this.selected_book.id, recipe: this.recipe.id}).then(r => { apiFactory.createRecipeBookEntry({book: this.selected_book.id, recipe: this.recipe.id}).then(r => {
this.recipe_book_list.push(r.data) this.recipe_book_list.push(r.data)
StandardToasts.makeStandardToast(StandardToasts.SUCCESS_CREATE) StandardToasts.makeStandardToast(this,StandardToasts.SUCCESS_CREATE)
}).catch(e => { }).catch(err => {
StandardToasts.makeStandardToast(StandardToasts.FAIL_UPDATE) StandardToasts.makeStandardToast(this,StandardToasts.FAIL_UPDATE, err)
}) })
}, },
removeFromBook: function (book_entry) { removeFromBook: function (book_entry) {
let apiFactory = new ApiApiFactory() let apiFactory = new ApiApiFactory()
apiFactory.destroyRecipeBookEntry(book_entry.id).then(r => { apiFactory.destroyRecipeBookEntry(book_entry.id).then(r => {
this.recipe_book_list = this.recipe_book_list.filter(e => e.id !== book_entry.id) this.recipe_book_list = this.recipe_book_list.filter(e => e.id !== book_entry.id)
StandardToasts.makeStandardToast(StandardToasts.SUCCESS_DELETE) StandardToasts.makeStandardToast(this,StandardToasts.SUCCESS_DELETE)
}) })
}, },
loadBookEntries: function () { loadBookEntries: function () {

View File

@@ -173,13 +173,13 @@ export default {
this.genericAPI(this.model, this.Actions.DELETE, { id: this.item1.id }) this.genericAPI(this.model, this.Actions.DELETE, { id: this.item1.id })
.then((result) => { .then((result) => {
this.$emit("finish-action") this.$emit("finish-action")
StandardToasts.makeStandardToast(StandardToasts.SUCCESS_DELETE) StandardToasts.makeStandardToast(this,StandardToasts.SUCCESS_DELETE)
}) })
.catch((err) => { .catch((err) => {
if (err.response.status === 403){ if (err.response.status === 403){
StandardToasts.makeStandardToast(StandardToasts.FAIL_DELETE_PROTECTED) StandardToasts.makeStandardToast(this,StandardToasts.FAIL_DELETE_PROTECTED, err)
}else { }else {
StandardToasts.makeStandardToast(StandardToasts.FAIL_DELETE) StandardToasts.makeStandardToast(this,StandardToasts.FAIL_DELETE, err)
} }
this.$emit("finish-action", "cancel") this.$emit("finish-action", "cancel")
}) })
@@ -190,22 +190,21 @@ export default {
this.genericAPI(this.model, this.Actions.CREATE, this.form_data) this.genericAPI(this.model, this.Actions.CREATE, this.form_data)
.then((result) => { .then((result) => {
this.$emit("finish-action", { item: result.data }) this.$emit("finish-action", { item: result.data })
StandardToasts.makeStandardToast(StandardToasts.SUCCESS_CREATE) StandardToasts.makeStandardToast(this,StandardToasts.SUCCESS_CREATE)
}) })
.catch((err) => { .catch((err) => {
console.log(err) console.log(err)
StandardToasts.makeStandardToast(StandardToasts.FAIL_CREATE) StandardToasts.makeStandardToast(this,StandardToasts.FAIL_CREATE)
this.$emit("finish-action", "cancel") this.$emit("finish-action", "cancel")
}) })
} else { } else {
this.genericAPI(this.model, this.Actions.UPDATE, this.form_data) this.genericAPI(this.model, this.Actions.UPDATE, this.form_data)
.then((result) => { .then((result) => {
this.$emit("finish-action") this.$emit("finish-action", { item: result.data })
StandardToasts.makeStandardToast(StandardToasts.SUCCESS_UPDATE) StandardToasts.makeStandardToast(this,StandardToasts.SUCCESS_UPDATE)
}) })
.catch((err) => { .catch((err) => {
console.log(err, err.response) StandardToasts.makeStandardToast(this,StandardToasts.FAIL_UPDATE, err)
StandardToasts.makeStandardToast(StandardToasts.FAIL_UPDATE)
this.$emit("finish-action", "cancel") this.$emit("finish-action", "cancel")
}) })
} }
@@ -224,11 +223,10 @@ export default {
this.genericAPI(this.model, this.Actions.MOVE, { source: this.item1.id, target: this.form_data.target.id }) this.genericAPI(this.model, this.Actions.MOVE, { source: this.item1.id, target: this.form_data.target.id })
.then((result) => { .then((result) => {
this.$emit("finish-action", { target: this.form_data.target.id }) this.$emit("finish-action", { target: this.form_data.target.id })
StandardToasts.makeStandardToast(StandardToasts.SUCCESS_MOVE) StandardToasts.makeStandardToast(this,StandardToasts.SUCCESS_MOVE)
}) })
.catch((err) => { .catch((err) => {
console.log(err) StandardToasts.makeStandardToast(this,StandardToasts.FAIL_MOVE, err)
StandardToasts.makeStandardToast(StandardToasts.FAIL_MOVE)
this.$emit("finish-action", "cancel") this.$emit("finish-action", "cancel")
}) })
}, },
@@ -248,13 +246,11 @@ export default {
target: this.form_data.target.id, target: this.form_data.target.id,
}) })
.then((result) => { .then((result) => {
this.$emit("finish-action", { target: this.form_data.target.id }) this.$emit("finish-action", { target: this.form_data.target.id, target_object: this.form_data.target }) //TODO temporary workaround to not change other apis
StandardToasts.makeStandardToast(StandardToasts.SUCCESS_MERGE) StandardToasts.makeStandardToast(this,StandardToasts.SUCCESS_MERGE)
}) })
.catch((err) => { .catch((err) => {
//TODO error checking not working with OpenAPI methods StandardToasts.makeStandardToast(this,StandardToasts.FAIL_MERGE, err)
console.log("Error", err)
StandardToasts.makeStandardToast(StandardToasts.FAIL_MERGE)
this.$emit("finish-action", "cancel") this.$emit("finish-action", "cancel")
}) })

View File

@@ -184,11 +184,11 @@ export default {
apiClient apiClient
.shoppingRecipe(this.recipe.id, shopping_recipe) .shoppingRecipe(this.recipe.id, shopping_recipe)
.then((result) => { .then((result) => {
StandardToasts.makeStandardToast(StandardToasts.SUCCESS_CREATE) StandardToasts.makeStandardToast(this,StandardToasts.SUCCESS_CREATE)
this.$emit("finish") this.$emit("finish")
}) })
.catch((err) => { .catch((err) => {
StandardToasts.makeStandardToast(StandardToasts.FAIL_CREATE) StandardToasts.makeStandardToast(this,StandardToasts.FAIL_CREATE, err)
}) })
this.$bvModal.hide(`shopping_${this.modal_id}`) this.$bvModal.hide(`shopping_${this.modal_id}`)

View File

@@ -162,10 +162,10 @@ export default {
this.servings_value = result.data.servings this.servings_value = result.data.servings
this.addToShopping() this.addToShopping()
} }
StandardToasts.makeStandardToast(StandardToasts.SUCCESS_CREATE) StandardToasts.makeStandardToast(this,StandardToasts.SUCCESS_CREATE)
}) })
.catch((error) => { .catch((err) => {
StandardToasts.makeStandardToast(StandardToasts.FAIL_CREATE) StandardToasts.makeStandardToast(this,StandardToasts.FAIL_CREATE, err)
}) })
}, },
createMealPlan(data) { createMealPlan(data) {
@@ -228,11 +228,11 @@ export default {
apiClient apiClient
.createRecipe(recipe) .createRecipe(recipe)
.then((new_recipe) => { .then((new_recipe) => {
StandardToasts.makeStandardToast(StandardToasts.SUCCESS_CREATE) StandardToasts.makeStandardToast(this,StandardToasts.SUCCESS_CREATE)
window.open(this.resolveDjangoUrl("view_recipe", new_recipe.data.id)) window.open(this.resolveDjangoUrl("view_recipe", new_recipe.data.id))
}) })
.catch((error) => { .catch((err) => {
StandardToasts.makeStandardToast(StandardToasts.FAIL_CREATE) StandardToasts.makeStandardToast(this,StandardToasts.FAIL_CREATE, err)
}) })
}) })
}, },

View File

@@ -1,34 +1,43 @@
<template> <template>
<div id="shopping_line_item"> <div id="shopping_line_item" class="pt-1">
<b-row align-h="start"> <b-row align-h="start" v-touch:start="startHandler" v-touch:moving="moveHandler" v-touch:end="endHandler"
<b-col cols="2" md="2" class="justify-content-start align-items-center d-flex d-md-none pr-0" v-if="settings.left_handed"> ref="shopping_line_item" class="invis-border">
<input type="checkbox" class="form-control form-control-sm checkbox-control-mobile" :checked="formatChecked" @change="updateChecked" :key="entries[0].id" /> <b-col cols="2" md="2" class="justify-content-start align-items-center d-flex d-md-none pr-0"
<b-button size="sm" @click="showDetails = !showDetails" class="d-inline-block d-md-none p-0" variant="link"> v-if="settings.left_handed">
<div class="text-nowrap"><i class="fa fa-chevron-right rotate" :class="showDetails ? 'rotated' : ''"></i></div> <input type="checkbox" class="form-control form-control-sm checkbox-control-mobile"
:checked="formatChecked" @change="updateChecked" :key="entries[0].id"/>
<b-button size="sm" @click="showDetails = !showDetails" class="d-inline-block d-md-none p-0"
variant="link">
<div class="text-nowrap"><i class="fa fa-chevron-right rotate"
:class="showDetails ? 'rotated' : ''"></i></div>
</b-button> </b-button>
</b-col> </b-col>
<b-col cols="1" class="align-items-center d-flex"> <b-col cols="1" class="align-items-center d-flex">
<div class="dropdown b-dropdown position-static inline-block" data-html2canvas-ignore="true" @click.stop="$emit('open-context-menu', $event, entries)"> <div class="dropdown b-dropdown position-static inline-block" data-html2canvas-ignore="true"
@click.stop="$emit('open-context-menu', $event, entries)">
<button <button
aria-haspopup="true" aria-haspopup="true"
aria-expanded="false" aria-expanded="false"
type="button" type="button"
:class="settings.left_handed ? 'dropdown-spacing' : ''" :class="settings.left_handed ? 'dropdown-spacing' : ''"
class="btn dropdown-toggle btn-link text-decoration-none text-body pr-0 pl-1 dropdown-toggle-no-caret" class="btn dropdown-toggle btn-link text-decoration-none text-body pr-0 pl-1 dropdown-toggle-no-caret">
>
<i class="fas fa-ellipsis-v"></i> <i class="fas fa-ellipsis-v"></i>
</button> </button>
</div> </div>
</b-col> </b-col>
<b-col cols="1" class="px-1 justify-content-center align-items-center d-none d-md-flex"> <b-col cols="1" class="px-1 justify-content-center align-items-center d-none d-md-flex">
<input type="checkbox" class="form-control form-control-sm checkbox-control" :checked="formatChecked" @change="updateChecked" :key="entries[0].id" /> <input type="checkbox" class="form-control form-control-sm checkbox-control"
:checked="formatChecked" @change="updateChecked" :key="entries[0].id"/>
</b-col> </b-col>
<b-col cols="8" > <b-col cols="8">
<b-row class="d-flex h-100"> <b-row class="d-flex h-100">
<b-col cols="6" md="3" class="d-flex align-items-center" v-if="Object.entries(formatAmount).length == 1"> <b-col cols="6" md="3" class="d-flex align-items-center"
<strong class="mr-1">{{ Object.entries(formatAmount)[0][1] }}</strong> {{ Object.entries(formatAmount)[0][0] }} v-if="Object.entries(formatAmount).length == 1">
<strong class="mr-1">{{ Object.entries(formatAmount)[0][1] }}</strong>
{{ Object.entries(formatAmount)[0][0] }}
</b-col> </b-col>
<b-col cols="6" md="3" class="d-flex flex-column" v-if="Object.entries(formatAmount).length != 1"> <b-col cols="6" md="3" class="d-flex flex-column"
v-if="Object.entries(formatAmount).length != 1">
<div class="small" v-for="(x, i) in Object.entries(formatAmount)" :key="i"> <div class="small" v-for="(x, i) in Object.entries(formatAmount)" :key="i">
{{ x[1] }} &ensp; {{ x[1] }} &ensp;
{{ x[0] }} {{ x[0] }}
@@ -38,20 +47,27 @@
<b-col cols="6" md="6" class="align-items-center d-flex pl-0 pr-0 pl-md-2 pr-md-2"> <b-col cols="6" md="6" class="align-items-center d-flex pl-0 pr-0 pl-md-2 pr-md-2">
{{ formatFood }} {{ formatFood }}
</b-col> </b-col>
<b-col cols="3" data-html2canvas-ignore="true" class="align-items-center d-none d-md-flex justify-content-end"> <b-col cols="3" data-html2canvas-ignore="true"
<b-button size="sm" @click="showDetails = !showDetails" class="p-0 mr-0 mr-md-2 p-md-2 text-decoration-none" variant="link"> class="align-items-center d-none d-md-flex justify-content-end">
<b-button size="sm" @click="showDetails = !showDetails"
class="p-0 mr-0 mr-md-2 p-md-2 text-decoration-none" variant="link">
<div class="text-nowrap"> <div class="text-nowrap">
<i class="fa fa-chevron-right rotate" :class="showDetails ? 'rotated' : ''"></i> <span class="d-none d-md-inline-block">{{ $t("Details") }}</span> <i class="fa fa-chevron-right rotate" :class="showDetails ? 'rotated' : ''"></i>
<span class="d-none d-md-inline-block">{{ $t("Details") }}</span>
</div> </div>
</b-button> </b-button>
</b-col> </b-col>
</b-row> </b-row>
</b-col> </b-col>
<b-col cols="2" class="justify-content-start align-items-center d-flex d-md-none pl-0 pr-0" v-if="!settings.left_handed"> <b-col cols="2" class="justify-content-start align-items-center d-flex d-md-none pl-0 pr-0"
<b-button size="sm" @click="showDetails = !showDetails" class="d-inline-block d-md-none p-0" variant="link"> v-if="!settings.left_handed">
<div class="text-nowrap"><i class="fa fa-chevron-right rotate" :class="showDetails ? 'rotated' : ''"></i></div> <b-button size="sm" @click="showDetails = !showDetails" class="d-inline-block d-md-none p-0"
variant="link">
<div class="text-nowrap"><i class="fa fa-chevron-right rotate"
:class="showDetails ? 'rotated' : ''"></i></div>
</b-button> </b-button>
<input type="checkbox" class="form-control form-control-sm checkbox-control-mobile" :checked="formatChecked" @change="updateChecked" :key="entries[0].id" /> <input type="checkbox" class="form-control form-control-sm checkbox-control-mobile"
:checked="formatChecked" @change="updateChecked" :key="entries[0].id"/>
</b-col> </b-col>
</b-row> </b-row>
<b-row align-h="center" class="d-none d-md-flex"> <b-row align-h="center" class="d-none d-md-flex">
@@ -83,11 +99,14 @@
</b-col> </b-col>
</b-row> </b-row>
<b-row align-h="start"> <b-row align-h="start">
<b-col cols="3" md="2" class="justify-content-start align-items-center d-flex d-md-none pr-0" v-if="settings.left_handed"> <b-col cols="3" md="2" class="justify-content-start align-items-center d-flex d-md-none pr-0"
<input type="checkbox" class="form-control form-control-sm checkbox-control-mobile" :checked="formatChecked" @change="updateChecked" :key="entries[0].id" /> v-if="settings.left_handed">
<input type="checkbox" class="form-control form-control-sm checkbox-control-mobile"
:checked="formatChecked" @change="updateChecked" :key="entries[0].id"/>
</b-col> </b-col>
<b-col cols="2" md="1" class="align-items-center d-flex"> <b-col cols="2" md="1" class="align-items-center d-flex">
<div class="dropdown b-dropdown position-static inline-block" data-html2canvas-ignore="true" @click.stop="$emit('open-context-menu', $event, e)"> <div class="dropdown b-dropdown position-static inline-block" data-html2canvas-ignore="true"
@click.stop="$emit('open-context-menu', $event, e)">
<button <button
aria-haspopup="true" aria-haspopup="true"
aria-expanded="false" aria-expanded="false"
@@ -100,7 +119,8 @@
</div> </div>
</b-col> </b-col>
<b-col cols="1" class="justify-content-center align-items-center d-none d-md-flex"> <b-col cols="1" class="justify-content-center align-items-center d-none d-md-flex">
<input type="checkbox" class="form-control form-control-sm checkbox-control" :checked="formatChecked" @change="updateChecked" :key="entries[0].id" /> <input type="checkbox" class="form-control form-control-sm checkbox-control"
:checked="formatChecked" @change="updateChecked" :key="entries[0].id"/>
</b-col> </b-col>
<b-col cols="7" md="9"> <b-col cols="7" md="9">
<b-row class="d-flex align-items-center h-100"> <b-row class="d-flex align-items-center h-100">
@@ -111,19 +131,23 @@
{{ formatOneFood(e) }} {{ formatOneFood(e) }}
</b-col> </b-col>
<b-col cols="12" class="d-flex d-md-none"> <b-col cols="12" class="d-flex d-md-none">
<div class="small text-muted text-truncate" v-for="(n, i) in formatOneNote(e)" :key="i">{{ n }}</div> <div class="small text-muted text-truncate" v-for="(n, i) in formatOneNote(e)"
:key="i">{{ n }}
</div>
</b-col> </b-col>
</b-row> </b-row>
</b-col> </b-col>
<b-col cols="3" md="2" class="justify-content-start align-items-center d-flex d-md-none" v-if="!settings.left_handed"> <b-col cols="3" md="2" class="justify-content-start align-items-center d-flex d-md-none"
<input type="checkbox" class="form-control form-control-sm checkbox-control-mobile" :checked="formatChecked" @change="updateChecked" :key="entries[0].id" /> v-if="!settings.left_handed">
<input type="checkbox" class="form-control form-control-sm checkbox-control-mobile"
:checked="formatChecked" @change="updateChecked" :key="entries[0].id"/>
</b-col> </b-col>
</b-row> </b-row>
<hr class="w-75" v-if="x !== entries.length - 1" /> <hr class="w-75 mt-1 mb-1 mt-md-3 mb-md-3" v-if="x !== entries.length - 1"/>
<div class="pb-4" v-if="x === entries.length - 1"></div> <div class="pb-1 pb-md-4" v-if="x === entries.length - 1"></div>
</div> </div>
</div> </div>
<hr class="m-1" v-if="!showDetails" /> <hr class="m-1" v-if="!showDetails"/>
<ContextMenu ref="recipe_card" triggers="click, hover" :title="$t('Filters')" style="max-width: 300"> <ContextMenu ref="recipe_card" triggers="click, hover" :title="$t('Filters')" style="max-width: 300">
<template #menu="{ contextData }" v-if="recipe"> <template #menu="{ contextData }" v-if="recipe">
<ContextMenuItem> <ContextMenuItem>
@@ -132,7 +156,8 @@
<ContextMenuItem @click="$refs.menu.close()"> <ContextMenuItem @click="$refs.menu.close()">
<b-form-group label-cols="9" content-cols="3" class="text-nowrap m-0 mr-2"> <b-form-group label-cols="9" content-cols="3" class="text-nowrap m-0 mr-2">
<template #label> <template #label>
<a class="dropdown-item p-2" href="#"><i class="fas fa-pizza-slice"></i> {{ $t("Servings") }}</a> <a class="dropdown-item p-2" href="#"><i class="fas fa-pizza-slice"></i>
{{ $t("Servings") }}</a>
</template> </template>
<div @click.prevent.stop> <div @click.prevent.stop>
<b-form-input class="mt-2" min="0" type="number" v-model="servings"></b-form-input> <b-form-input class="mt-2" min="0" type="number" v-model="servings"></b-form-input>
@@ -141,38 +166,45 @@
</ContextMenuItem> </ContextMenuItem>
</template> </template>
</ContextMenu> </ContextMenu>
<i class="fa fa-hourglass fa-lg" style="display: none; position: absolute" aria-hidden="true"
ref="delay_icon"></i>
<i class="fa fa-check fa-lg" style="display: none; position: absolute" aria-hidden="true" ref="check_icon"></i>
</div> </div>
</template> </template>
<script> <script>
import Vue from "vue" import Vue from "vue"
import { BootstrapVue } from "bootstrap-vue" import {BootstrapVue} from "bootstrap-vue"
import "bootstrap-vue/dist/bootstrap-vue.css" import "bootstrap-vue/dist/bootstrap-vue.css"
import ContextMenu from "@/components/ContextMenu/ContextMenu" import ContextMenu from "@/components/ContextMenu/ContextMenu"
import ContextMenuItem from "@/components/ContextMenu/ContextMenuItem" import ContextMenuItem from "@/components/ContextMenu/ContextMenuItem"
import { ApiMixin } from "@/utils/utils" import {ApiMixin} from "@/utils/utils"
import RecipeCard from "./RecipeCard.vue" import RecipeCard from "./RecipeCard.vue"
import Vue2TouchEvents from "vue2-touch-events"
Vue.use(BootstrapVue) Vue.use(BootstrapVue)
Vue.use(Vue2TouchEvents)
export default { export default {
// TODO ApiGenerator doesn't capture and share error information - would be nice to share error details when available // TODO ApiGenerator doesn't capture and share error information - would be nice to share error details when available
// or i'm capturing it incorrectly // or i'm capturing it incorrectly
name: "ShoppingLineItem", name: "ShoppingLineItem",
mixins: [ApiMixin], mixins: [ApiMixin],
components: { RecipeCard, ContextMenu, ContextMenuItem }, components: {RecipeCard, ContextMenu, ContextMenuItem},
props: { props: {
entries: { entries: {
type: Array, type: Array,
}, },
settings: Object, settings: Object,
groupby: { type: String }, groupby: {type: String},
}, },
data() { data() {
return { return {
showDetails: false, showDetails: false,
recipe: undefined, recipe: undefined,
servings: 1, servings: 1,
dragStartX: 0,
distance_left: 0
} }
}, },
computed: { computed: {
@@ -249,6 +281,71 @@ export default {
timeStyle: "short", timeStyle: "short",
}).format(Date.parse(datetime)) }).format(Date.parse(datetime))
}, },
startHandler: function (event) {
if (event.changedTouches.length > 0) {
this.dragStartX = event.changedTouches[0].clientX
}
},
getOffset(el) {
let rect = el.getBoundingClientRect();
return {
left: rect.left + window.scrollX,
top: rect.top + window.scrollY,
right: rect.right - window.scrollX,
};
},
moveHandler: function (event) {
let item = this.$refs['shopping_line_item'];
this.distance_left = event.changedTouches[0].clientX - this.dragStartX;
item.style.marginLeft = this.distance_left
item.style.marginRight = -this.distance_left
item.style.backgroundColor = '#ddbf86'
item.style.border = "1px solid #000"
let delay_icon = this.$refs['delay_icon']
let check_icon = this.$refs['check_icon']
let color_factor = Math.abs(this.distance_left) / 100
if (this.distance_left > 0) {
item.parentElement.parentElement.style.backgroundColor = 'rgba(130,170,139,0)'.replace(/[^,]+(?=\))/, color_factor)
check_icon.style.display = "block"
check_icon.style.left = this.getOffset(item.parentElement.parentElement).left + 40
check_icon.style.top = this.getOffset(item.parentElement.parentElement).top - 92
check_icon.style.opacity = color_factor - 0.3
} else {
item.parentElement.parentElement.style.backgroundColor = 'rgba(185,135,102,0)'.replace(/[^,]+(?=\))/, color_factor)
delay_icon.style.display = "block"
console.log(item.parentElement.parentElement.clientWidth)
delay_icon.style.left = this.getOffset(item.parentElement.parentElement).right - 40
delay_icon.style.top = this.getOffset(item.parentElement.parentElement).top - 92
delay_icon.style.opacity = color_factor - 0.3
}
},
endHandler: function (event) {
let item = this.$refs['shopping_line_item'];
item.removeAttribute('style');
item.parentElement.parentElement.removeAttribute('style');
let delay_icon = this.$refs['delay_icon']
let check_icon = this.$refs['check_icon']
delay_icon.style.display = "none"
check_icon.style.display = "none"
if (Math.abs(this.distance_left) > window.screen.width / 6) {
if (this.distance_left > 0) {
let checked = false;
this.entries.forEach((cur) => {
checked = cur.checked
})
let update = {entries: this.entries.map((x) => x.id), checked: !checked}
this.$emit("update-checkbox", update)
} else {
this.$emit("update-delaythis", this.entries)
}
}
},
formatOneAmount: function (item) { formatOneAmount: function (item) {
return item?.amount ?? 1 return item?.amount ?? 1
}, },
@@ -289,7 +386,7 @@ export default {
return [this.$t("Added_by"), item?.created_by.username, "@", this.formatDate(item.created_at)].join(" ") return [this.$t("Added_by"), item?.created_by.username, "@", this.formatDate(item.created_at)].join(" ")
}, },
openRecipeCard: function (e, item) { openRecipeCard: function (e, item) {
this.genericAPI(this.Models.RECIPE, this.Actions.FETCH, { id: item.recipe_mealplan.recipe }).then((result) => { this.genericAPI(this.Models.RECIPE, this.Actions.FETCH, {id: item.recipe_mealplan.recipe}).then((result) => {
let recipe = result.data let recipe = result.data
recipe.steps = undefined recipe.steps = undefined
this.recipe = true this.recipe = true
@@ -299,10 +396,11 @@ export default {
updateChecked: function (e, item) { updateChecked: function (e, item) {
let update = undefined let update = undefined
if (!item) { if (!item) {
update = { entries: this.entries.map((x) => x.id), checked: !this.formatChecked } update = {entries: this.entries.map((x) => x.id), checked: !this.formatChecked}
} else { } else {
update = { entries: [item], checked: !item.checked } update = {entries: [item], checked: !item.checked}
} }
console.log(update)
this.$emit("update-checkbox", update) this.$emit("update-checkbox", update)
}, },
}, },
@@ -351,4 +449,8 @@ export default {
padding-right: 0 !important; padding-right: 0 !important;
} }
} }
.invis-border {
border: 1px solid transparent;
}
</style> </style>

View File

@@ -114,7 +114,7 @@
"Create_New_Shopping Category": "Neue Einkaufskategorie erstellen", "Create_New_Shopping Category": "Neue Einkaufskategorie erstellen",
"Automate": "Automatisieren", "Automate": "Automatisieren",
"Type": "Typ", "Type": "Typ",
"and_up": "& Hoch", "and_up": "& Höher",
"Unrated": "Unbewertet", "Unrated": "Unbewertet",
"Shopping_list": "Einkaufsliste", "Shopping_list": "Einkaufsliste",
"step_time_minutes": "Schritt Dauer in Minuten", "step_time_minutes": "Schritt Dauer in Minuten",
@@ -217,7 +217,7 @@
"Inherit": "Vererben", "Inherit": "Vererben",
"InheritFields": "Feldwerte vererben", "InheritFields": "Feldwerte vererben",
"ShowUncategorizedFood": "Zeige nicht zugeordnete", "ShowUncategorizedFood": "Zeige nicht zugeordnete",
"DelayFor": "Um {hours } verschieben", "DelayFor": "Um {hours} Stunden verschieben",
"Warning": "Warnung", "Warning": "Warnung",
"NoCategory": "Keine Kategorie ausgewählt.", "NoCategory": "Keine Kategorie ausgewählt.",
"ShowDelayed": "Zeige verschobene Elemente", "ShowDelayed": "Zeige verschobene Elemente",
@@ -283,7 +283,7 @@
"copy_markdown_table": "Als Markdown-Tabelle kopieren", "copy_markdown_table": "Als Markdown-Tabelle kopieren",
"in_shopping": "In Einkaufsliste", "in_shopping": "In Einkaufsliste",
"DelayUntil": "Verzögerung bis", "DelayUntil": "Verzögerung bis",
"QuickEntry": "Schnelleinstieg", "QuickEntry": "Einfach",
"shopping_add_onhand": "Automatisch vorrätig", "shopping_add_onhand": "Automatisch vorrätig",
"related_recipes": "Ähnliche Rezepte", "related_recipes": "Ähnliche Rezepte",
"today_recipes": "Rezepte des Tages", "today_recipes": "Rezepte des Tages",
@@ -354,5 +354,24 @@
"Page": "Seite", "Page": "Seite",
"Reset": "Zurücksetzen", "Reset": "Zurücksetzen",
"search_rank": "Such-Rang", "search_rank": "Such-Rang",
"paste_ingredients": "Zutaten einfügen" "paste_ingredients": "Zutaten einfügen",
"Ingredient Editor": "Zutateneditor",
"Protected": "Geschützt",
"not": "nicht",
"warning_duplicate_filter": "Warnung: Wegen technischen Limitierungen können mehrere Filter der selben Kombination (und/oder/nicht) zu unerwarteten Ergebnissen führen.",
"and_down": "& Niedriger",
"enable_expert": "Expertenmodus aktivieren",
"filter_name": "Name des Filters",
"shared_with": "Geteilt mit",
"asc": "Aufsteigend",
"desc": "Absteigend",
"book_filter_help": "Schließt zusätzlich zu den manuell hinzugefügten Rezepte, alle Rezepte die dem Filter entsprechen ein.",
"recipe_name": "Rezeptname",
"paste_ingredients_placeholder": "Zutatenliste hier einfügen",
"ingredient_list": "Zutatenliste",
"filter": "Filter",
"err_deleting_protected_resource": "Das Objekt, das du versuchst zu löschen, wird noch benutzt und kann nicht gelöscht werden.",
"Create Food": "Zutat erstellen",
"additional_options": "Weitere Möglichkeiten",
"create_food_desc": "Zutat erstellen und mit diesem Rezept verknüpfen"
} }

View File

@@ -243,6 +243,7 @@
"OfflineAlert": "You are offline, shopping list may not syncronize.", "OfflineAlert": "You are offline, shopping list may not syncronize.",
"shopping_share": "Share Shopping List", "shopping_share": "Share Shopping List",
"shopping_auto_sync": "Autosync", "shopping_auto_sync": "Autosync",
"one_url_per_line": "One URL per line",
"mealplan_autoadd_shopping": "Auto Add Meal Plan", "mealplan_autoadd_shopping": "Auto Add Meal Plan",
"mealplan_autoexclude_onhand": "Exclude Food On Hand", "mealplan_autoexclude_onhand": "Exclude Food On Hand",
"mealplan_autoinclude_related": "Add Related Recipes", "mealplan_autoinclude_related": "Add Related Recipes",
@@ -339,8 +340,11 @@
"Website": "Website", "Website": "Website",
"App": "App", "App": "App",
"Bookmarklet": "Bookmarklet", "Bookmarklet": "Bookmarklet",
"click_image_import": "Click the image you want to import for this recipe",
"no_more_images_found": "No additional images found on Website.",
"import_duplicates": "To prevent duplicates recipes with the same name as existing ones are ignored. Check this box to import everything.", "import_duplicates": "To prevent duplicates recipes with the same name as existing ones are ignored. Check this box to import everything.",
"paste_json": "Paste json or html source here to load recipe.", "paste_json": "Paste json or html source here to load recipe.",
"Click_To_Edit": "Click to edit",
"search_no_recipes": "Could not find any recipes!", "search_no_recipes": "Could not find any recipes!",
"search_import_help_text": "Import a recipe from an external website or application.", "search_import_help_text": "Import a recipe from an external website or application.",
"search_create_help_text": "Create a new recipe directly in Tandoor.", "search_create_help_text": "Create a new recipe directly in Tandoor.",
@@ -386,7 +390,15 @@
"Advanced": "Advanced", "Advanced": "Advanced",
"Page": "Page", "Page": "Page",
"Reset": "Reset", "Reset": "Reset",
"Options": "Options",
"Create Food": "Create Food", "Create Food": "Create Food",
"create_food_desc": "Create a food and link it to this recipe.", "create_food_desc": "Create a food and link it to this recipe.",
"additional_options": "Additional Options" "additional_options": "Additional Options",
"Importer_Help": "More information and help on this importer:",
"Documentation": "Documentation",
"Select_App_To_Import": "Please select an App to Import from",
"Import_Supported": "Import supported",
"Export_Supported": "Export supported",
"Import_Not_Yet_Supported": "Import not yet supported",
"Export_Not_Yet_Supported": "Export not yet supported"
} }

View File

@@ -1,7 +1,7 @@
// containing all data and functions regarding the different integrations // containing all data and functions regarding the different integrations
export const INTEGRATIONS = [ export const INTEGRATIONS = [
{id: 'DEFAULT', name: "Tandoor", import: true, export: true, help_url: 'https://docs.tandoor.dev/features/import_export/#default'}, {id: 'DEFAULT', name: "Tandoor", import: true, export: true, help_url: 'https://docs.tandoor.dev/features/import_export/#default', img_src: 'https://raw.githubusercontent.com/TandoorRecipes/recipes/develop/docs/logo_color.svg'},
{id: 'CHEFTAP', name: "Cheftap", import: true, export: false, help_url: 'https://docs.tandoor.dev/features/import_export/#cheftap'}, {id: 'CHEFTAP', name: "Cheftap", import: true, export: false, help_url: 'https://docs.tandoor.dev/features/import_export/#cheftap'},
{id: 'CHOWDOWN', name: "Chowdown", import: true, export: false, help_url: 'https://docs.tandoor.dev/features/import_export/#chowdown'}, {id: 'CHOWDOWN', name: "Chowdown", import: true, export: false, help_url: 'https://docs.tandoor.dev/features/import_export/#chowdown'},
{id: 'COOKBOOKAPP', name: "CookBookApp", import: true, export: false, help_url: 'https://docs.tandoor.dev/features/import_export/#cookbookapp'}, {id: 'COOKBOOKAPP', name: "CookBookApp", import: true, export: false, help_url: 'https://docs.tandoor.dev/features/import_export/#cookbookapp'},

View File

@@ -987,9 +987,40 @@ export interface InlineResponse20010 {
previous?: string | null; previous?: string | null;
/** /**
* *
* @type {Array<ViewLog>} * @type {Array<Unit>}
* @memberof InlineResponse20010 * @memberof InlineResponse20010
*/ */
results?: Array<Unit>;
}
/**
*
* @export
* @interface InlineResponse20011
*/
export interface InlineResponse20011 {
/**
*
* @type {number}
* @memberof InlineResponse20011
*/
count?: number;
/**
*
* @type {string}
* @memberof InlineResponse20011
*/
next?: string | null;
/**
*
* @type {string}
* @memberof InlineResponse20011
*/
previous?: string | null;
/**
*
* @type {Array<ViewLog>}
* @memberof InlineResponse20011
*/
results?: Array<ViewLog>; results?: Array<ViewLog>;
} }
/** /**
@@ -1080,10 +1111,10 @@ export interface InlineResponse2004 {
previous?: string | null; previous?: string | null;
/** /**
* *
* @type {Array<Keyword>} * @type {Array<Ingredient>}
* @memberof InlineResponse2004 * @memberof InlineResponse2004
*/ */
results?: Array<Keyword>; results?: Array<Ingredient>;
} }
/** /**
* *
@@ -1111,10 +1142,10 @@ export interface InlineResponse2005 {
previous?: string | null; previous?: string | null;
/** /**
* *
* @type {Array<RecipeOverview>} * @type {Array<Keyword>}
* @memberof InlineResponse2005 * @memberof InlineResponse2005
*/ */
results?: Array<RecipeOverview>; results?: Array<Keyword>;
} }
/** /**
* *
@@ -1142,10 +1173,10 @@ export interface InlineResponse2006 {
previous?: string | null; previous?: string | null;
/** /**
* *
* @type {Array<Step>} * @type {Array<RecipeOverview>}
* @memberof InlineResponse2006 * @memberof InlineResponse2006
*/ */
results?: Array<Step>; results?: Array<RecipeOverview>;
} }
/** /**
* *
@@ -1173,10 +1204,10 @@ export interface InlineResponse2007 {
previous?: string | null; previous?: string | null;
/** /**
* *
* @type {Array<SupermarketCategoryRelation>} * @type {Array<Step>}
* @memberof InlineResponse2007 * @memberof InlineResponse2007
*/ */
results?: Array<SupermarketCategoryRelation>; results?: Array<Step>;
} }
/** /**
* *
@@ -1204,10 +1235,10 @@ export interface InlineResponse2008 {
previous?: string | null; previous?: string | null;
/** /**
* *
* @type {Array<SyncLog>} * @type {Array<SupermarketCategoryRelation>}
* @memberof InlineResponse2008 * @memberof InlineResponse2008
*/ */
results?: Array<SyncLog>; results?: Array<SupermarketCategoryRelation>;
} }
/** /**
* *
@@ -1235,10 +1266,10 @@ export interface InlineResponse2009 {
previous?: string | null; previous?: string | null;
/** /**
* *
* @type {Array<Unit>} * @type {Array<SyncLog>}
* @memberof InlineResponse2009 * @memberof InlineResponse2009
*/ */
results?: Array<Unit>; results?: Array<SyncLog>;
} }
/** /**
* *
@@ -5614,10 +5645,12 @@ export const ApiApiAxiosParamCreator = function (configuration?: Configuration)
}, },
/** /**
* *
* @param {number} [page] A page number within the paginated result set.
* @param {number} [pageSize] Number of results to return per page.
* @param {*} [options] Override http request option. * @param {*} [options] Override http request option.
* @throws {RequiredError} * @throws {RequiredError}
*/ */
listIngredients: async (options: any = {}): Promise<RequestArgs> => { listIngredients: async (page?: number, pageSize?: number, options: any = {}): Promise<RequestArgs> => {
const localVarPath = `/api/ingredient/`; const localVarPath = `/api/ingredient/`;
// use dummy base URL string because the URL constructor only accepts absolute URLs. // use dummy base URL string because the URL constructor only accepts absolute URLs.
const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL); const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL);
@@ -5630,6 +5663,14 @@ export const ApiApiAxiosParamCreator = function (configuration?: Configuration)
const localVarHeaderParameter = {} as any; const localVarHeaderParameter = {} as any;
const localVarQueryParameter = {} as any; const localVarQueryParameter = {} as any;
if (page !== undefined) {
localVarQueryParameter['page'] = page;
}
if (pageSize !== undefined) {
localVarQueryParameter['page_size'] = pageSize;
}
setSearchParams(localVarUrlObj, localVarQueryParameter, options.query); setSearchParams(localVarUrlObj, localVarQueryParameter, options.query);
@@ -10494,11 +10535,13 @@ export const ApiApiFp = function(configuration?: Configuration) {
}, },
/** /**
* *
* @param {number} [page] A page number within the paginated result set.
* @param {number} [pageSize] Number of results to return per page.
* @param {*} [options] Override http request option. * @param {*} [options] Override http request option.
* @throws {RequiredError} * @throws {RequiredError}
*/ */
async listIngredients(options?: any): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<Array<Ingredient>>> { async listIngredients(page?: number, pageSize?: number, options?: any): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<InlineResponse2004>> {
const localVarAxiosArgs = await localVarAxiosParamCreator.listIngredients(options); const localVarAxiosArgs = await localVarAxiosParamCreator.listIngredients(page, pageSize, options);
return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration);
}, },
/** /**
@@ -10511,7 +10554,7 @@ export const ApiApiFp = function(configuration?: Configuration) {
* @param {*} [options] Override http request option. * @param {*} [options] Override http request option.
* @throws {RequiredError} * @throws {RequiredError}
*/ */
async listKeywords(query?: string, root?: number, tree?: number, page?: number, pageSize?: number, options?: any): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<InlineResponse2004>> { async listKeywords(query?: string, root?: number, tree?: number, page?: number, pageSize?: number, options?: any): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<InlineResponse2005>> {
const localVarAxiosArgs = await localVarAxiosParamCreator.listKeywords(query, root, tree, page, pageSize, options); const localVarAxiosArgs = await localVarAxiosParamCreator.listKeywords(query, root, tree, page, pageSize, options);
return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration);
}, },
@@ -10585,7 +10628,7 @@ export const ApiApiFp = function(configuration?: Configuration) {
* @param {*} [options] Override http request option. * @param {*} [options] Override http request option.
* @throws {RequiredError} * @throws {RequiredError}
*/ */
async listRecipes(query?: string, keywords?: number, keywordsOr?: number, keywordsAnd?: number, keywordsOrNot?: number, keywordsAndNot?: number, foods?: number, foodsOr?: number, foodsAnd?: number, foodsOrNot?: number, foodsAndNot?: number, units?: number, rating?: number, books?: string, booksOr?: number, booksAnd?: number, booksOrNot?: number, booksAndNot?: number, internal?: string, random?: string, _new?: string, timescooked?: number, cookedon?: string, createdon?: string, updatedon?: string, viewedon?: string, makenow?: string, page?: number, pageSize?: number, options?: any): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<InlineResponse2005>> { async listRecipes(query?: string, keywords?: number, keywordsOr?: number, keywordsAnd?: number, keywordsOrNot?: number, keywordsAndNot?: number, foods?: number, foodsOr?: number, foodsAnd?: number, foodsOrNot?: number, foodsAndNot?: number, units?: number, rating?: number, books?: string, booksOr?: number, booksAnd?: number, booksOrNot?: number, booksAndNot?: number, internal?: string, random?: string, _new?: string, timescooked?: number, cookedon?: string, createdon?: string, updatedon?: string, viewedon?: string, makenow?: string, page?: number, pageSize?: number, options?: any): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<InlineResponse2006>> {
const localVarAxiosArgs = await localVarAxiosParamCreator.listRecipes(query, keywords, keywordsOr, keywordsAnd, keywordsOrNot, keywordsAndNot, foods, foodsOr, foodsAnd, foodsOrNot, foodsAndNot, units, rating, books, booksOr, booksAnd, booksOrNot, booksAndNot, internal, random, _new, timescooked, cookedon, createdon, updatedon, viewedon, makenow, page, pageSize, options); const localVarAxiosArgs = await localVarAxiosParamCreator.listRecipes(query, keywords, keywordsOr, keywordsAnd, keywordsOrNot, keywordsAndNot, foods, foodsOr, foodsAnd, foodsOrNot, foodsAndNot, units, rating, books, booksOr, booksAnd, booksOrNot, booksAndNot, internal, random, _new, timescooked, cookedon, createdon, updatedon, viewedon, makenow, page, pageSize, options);
return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration);
}, },
@@ -10628,7 +10671,7 @@ export const ApiApiFp = function(configuration?: Configuration) {
* @param {*} [options] Override http request option. * @param {*} [options] Override http request option.
* @throws {RequiredError} * @throws {RequiredError}
*/ */
async listSteps(recipe?: number, query?: string, page?: number, pageSize?: number, options?: any): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<InlineResponse2006>> { async listSteps(recipe?: number, query?: string, page?: number, pageSize?: number, options?: any): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<InlineResponse2007>> {
const localVarAxiosArgs = await localVarAxiosParamCreator.listSteps(recipe, query, page, pageSize, options); const localVarAxiosArgs = await localVarAxiosParamCreator.listSteps(recipe, query, page, pageSize, options);
return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration);
}, },
@@ -10648,7 +10691,7 @@ export const ApiApiFp = function(configuration?: Configuration) {
* @param {*} [options] Override http request option. * @param {*} [options] Override http request option.
* @throws {RequiredError} * @throws {RequiredError}
*/ */
async listSupermarketCategoryRelations(page?: number, pageSize?: number, options?: any): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<InlineResponse2007>> { async listSupermarketCategoryRelations(page?: number, pageSize?: number, options?: any): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<InlineResponse2008>> {
const localVarAxiosArgs = await localVarAxiosParamCreator.listSupermarketCategoryRelations(page, pageSize, options); const localVarAxiosArgs = await localVarAxiosParamCreator.listSupermarketCategoryRelations(page, pageSize, options);
return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration);
}, },
@@ -10677,7 +10720,7 @@ export const ApiApiFp = function(configuration?: Configuration) {
* @param {*} [options] Override http request option. * @param {*} [options] Override http request option.
* @throws {RequiredError} * @throws {RequiredError}
*/ */
async listSyncLogs(page?: number, pageSize?: number, options?: any): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<InlineResponse2008>> { async listSyncLogs(page?: number, pageSize?: number, options?: any): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<InlineResponse2009>> {
const localVarAxiosArgs = await localVarAxiosParamCreator.listSyncLogs(page, pageSize, options); const localVarAxiosArgs = await localVarAxiosParamCreator.listSyncLogs(page, pageSize, options);
return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration);
}, },
@@ -10698,7 +10741,7 @@ export const ApiApiFp = function(configuration?: Configuration) {
* @param {*} [options] Override http request option. * @param {*} [options] Override http request option.
* @throws {RequiredError} * @throws {RequiredError}
*/ */
async listUnits(query?: string, page?: number, pageSize?: number, options?: any): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<InlineResponse2009>> { async listUnits(query?: string, page?: number, pageSize?: number, options?: any): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<InlineResponse20010>> {
const localVarAxiosArgs = await localVarAxiosParamCreator.listUnits(query, page, pageSize, options); const localVarAxiosArgs = await localVarAxiosParamCreator.listUnits(query, page, pageSize, options);
return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration);
}, },
@@ -10736,7 +10779,7 @@ export const ApiApiFp = function(configuration?: Configuration) {
* @param {*} [options] Override http request option. * @param {*} [options] Override http request option.
* @throws {RequiredError} * @throws {RequiredError}
*/ */
async listViewLogs(page?: number, pageSize?: number, options?: any): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<InlineResponse20010>> { async listViewLogs(page?: number, pageSize?: number, options?: any): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<InlineResponse20011>> {
const localVarAxiosArgs = await localVarAxiosParamCreator.listViewLogs(page, pageSize, options); const localVarAxiosArgs = await localVarAxiosParamCreator.listViewLogs(page, pageSize, options);
return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration);
}, },
@@ -12319,11 +12362,13 @@ export const ApiApiFactory = function (configuration?: Configuration, basePath?:
}, },
/** /**
* *
* @param {number} [page] A page number within the paginated result set.
* @param {number} [pageSize] Number of results to return per page.
* @param {*} [options] Override http request option. * @param {*} [options] Override http request option.
* @throws {RequiredError} * @throws {RequiredError}
*/ */
listIngredients(options?: any): AxiosPromise<Array<Ingredient>> { listIngredients(page?: number, pageSize?: number, options?: any): AxiosPromise<InlineResponse2004> {
return localVarFp.listIngredients(options).then((request) => request(axios, basePath)); return localVarFp.listIngredients(page, pageSize, options).then((request) => request(axios, basePath));
}, },
/** /**
* *
@@ -12335,7 +12380,7 @@ export const ApiApiFactory = function (configuration?: Configuration, basePath?:
* @param {*} [options] Override http request option. * @param {*} [options] Override http request option.
* @throws {RequiredError} * @throws {RequiredError}
*/ */
listKeywords(query?: string, root?: number, tree?: number, page?: number, pageSize?: number, options?: any): AxiosPromise<InlineResponse2004> { listKeywords(query?: string, root?: number, tree?: number, page?: number, pageSize?: number, options?: any): AxiosPromise<InlineResponse2005> {
return localVarFp.listKeywords(query, root, tree, page, pageSize, options).then((request) => request(axios, basePath)); return localVarFp.listKeywords(query, root, tree, page, pageSize, options).then((request) => request(axios, basePath));
}, },
/** /**
@@ -12404,7 +12449,7 @@ export const ApiApiFactory = function (configuration?: Configuration, basePath?:
* @param {*} [options] Override http request option. * @param {*} [options] Override http request option.
* @throws {RequiredError} * @throws {RequiredError}
*/ */
listRecipes(query?: string, keywords?: number, keywordsOr?: number, keywordsAnd?: number, keywordsOrNot?: number, keywordsAndNot?: number, foods?: number, foodsOr?: number, foodsAnd?: number, foodsOrNot?: number, foodsAndNot?: number, units?: number, rating?: number, books?: string, booksOr?: number, booksAnd?: number, booksOrNot?: number, booksAndNot?: number, internal?: string, random?: string, _new?: string, timescooked?: number, cookedon?: string, createdon?: string, updatedon?: string, viewedon?: string, makenow?: string, page?: number, pageSize?: number, options?: any): AxiosPromise<InlineResponse2005> { listRecipes(query?: string, keywords?: number, keywordsOr?: number, keywordsAnd?: number, keywordsOrNot?: number, keywordsAndNot?: number, foods?: number, foodsOr?: number, foodsAnd?: number, foodsOrNot?: number, foodsAndNot?: number, units?: number, rating?: number, books?: string, booksOr?: number, booksAnd?: number, booksOrNot?: number, booksAndNot?: number, internal?: string, random?: string, _new?: string, timescooked?: number, cookedon?: string, createdon?: string, updatedon?: string, viewedon?: string, makenow?: string, page?: number, pageSize?: number, options?: any): AxiosPromise<InlineResponse2006> {
return localVarFp.listRecipes(query, keywords, keywordsOr, keywordsAnd, keywordsOrNot, keywordsAndNot, foods, foodsOr, foodsAnd, foodsOrNot, foodsAndNot, units, rating, books, booksOr, booksAnd, booksOrNot, booksAndNot, internal, random, _new, timescooked, cookedon, createdon, updatedon, viewedon, makenow, page, pageSize, options).then((request) => request(axios, basePath)); return localVarFp.listRecipes(query, keywords, keywordsOr, keywordsAnd, keywordsOrNot, keywordsAndNot, foods, foodsOr, foodsAnd, foodsOrNot, foodsAndNot, units, rating, books, booksOr, booksAnd, booksOrNot, booksAndNot, internal, random, _new, timescooked, cookedon, createdon, updatedon, viewedon, makenow, page, pageSize, options).then((request) => request(axios, basePath));
}, },
/** /**
@@ -12443,7 +12488,7 @@ export const ApiApiFactory = function (configuration?: Configuration, basePath?:
* @param {*} [options] Override http request option. * @param {*} [options] Override http request option.
* @throws {RequiredError} * @throws {RequiredError}
*/ */
listSteps(recipe?: number, query?: string, page?: number, pageSize?: number, options?: any): AxiosPromise<InlineResponse2006> { listSteps(recipe?: number, query?: string, page?: number, pageSize?: number, options?: any): AxiosPromise<InlineResponse2007> {
return localVarFp.listSteps(recipe, query, page, pageSize, options).then((request) => request(axios, basePath)); return localVarFp.listSteps(recipe, query, page, pageSize, options).then((request) => request(axios, basePath));
}, },
/** /**
@@ -12461,7 +12506,7 @@ export const ApiApiFactory = function (configuration?: Configuration, basePath?:
* @param {*} [options] Override http request option. * @param {*} [options] Override http request option.
* @throws {RequiredError} * @throws {RequiredError}
*/ */
listSupermarketCategoryRelations(page?: number, pageSize?: number, options?: any): AxiosPromise<InlineResponse2007> { listSupermarketCategoryRelations(page?: number, pageSize?: number, options?: any): AxiosPromise<InlineResponse2008> {
return localVarFp.listSupermarketCategoryRelations(page, pageSize, options).then((request) => request(axios, basePath)); return localVarFp.listSupermarketCategoryRelations(page, pageSize, options).then((request) => request(axios, basePath));
}, },
/** /**
@@ -12487,7 +12532,7 @@ export const ApiApiFactory = function (configuration?: Configuration, basePath?:
* @param {*} [options] Override http request option. * @param {*} [options] Override http request option.
* @throws {RequiredError} * @throws {RequiredError}
*/ */
listSyncLogs(page?: number, pageSize?: number, options?: any): AxiosPromise<InlineResponse2008> { listSyncLogs(page?: number, pageSize?: number, options?: any): AxiosPromise<InlineResponse2009> {
return localVarFp.listSyncLogs(page, pageSize, options).then((request) => request(axios, basePath)); return localVarFp.listSyncLogs(page, pageSize, options).then((request) => request(axios, basePath));
}, },
/** /**
@@ -12506,7 +12551,7 @@ export const ApiApiFactory = function (configuration?: Configuration, basePath?:
* @param {*} [options] Override http request option. * @param {*} [options] Override http request option.
* @throws {RequiredError} * @throws {RequiredError}
*/ */
listUnits(query?: string, page?: number, pageSize?: number, options?: any): AxiosPromise<InlineResponse2009> { listUnits(query?: string, page?: number, pageSize?: number, options?: any): AxiosPromise<InlineResponse20010> {
return localVarFp.listUnits(query, page, pageSize, options).then((request) => request(axios, basePath)); return localVarFp.listUnits(query, page, pageSize, options).then((request) => request(axios, basePath));
}, },
/** /**
@@ -12540,7 +12585,7 @@ export const ApiApiFactory = function (configuration?: Configuration, basePath?:
* @param {*} [options] Override http request option. * @param {*} [options] Override http request option.
* @throws {RequiredError} * @throws {RequiredError}
*/ */
listViewLogs(page?: number, pageSize?: number, options?: any): AxiosPromise<InlineResponse20010> { listViewLogs(page?: number, pageSize?: number, options?: any): AxiosPromise<InlineResponse20011> {
return localVarFp.listViewLogs(page, pageSize, options).then((request) => request(axios, basePath)); return localVarFp.listViewLogs(page, pageSize, options).then((request) => request(axios, basePath));
}, },
/** /**
@@ -14156,12 +14201,14 @@ export class ApiApi extends BaseAPI {
/** /**
* *
* @param {number} [page] A page number within the paginated result set.
* @param {number} [pageSize] Number of results to return per page.
* @param {*} [options] Override http request option. * @param {*} [options] Override http request option.
* @throws {RequiredError} * @throws {RequiredError}
* @memberof ApiApi * @memberof ApiApi
*/ */
public listIngredients(options?: any) { public listIngredients(page?: number, pageSize?: number, options?: any) {
return ApiApiFp(this.configuration).listIngredients(options).then((request) => request(this.axios, this.basePath)); return ApiApiFp(this.configuration).listIngredients(page, pageSize, options).then((request) => request(this.axios, this.basePath));
} }
/** /**

View File

@@ -50,51 +50,142 @@ export class StandardToasts {
static FAIL_MOVE = "FAIL_MOVE" static FAIL_MOVE = "FAIL_MOVE"
static FAIL_MERGE = "FAIL_MERGE" static FAIL_MERGE = "FAIL_MERGE"
static makeStandardToast(toast, err_details = undefined) { //TODO err_details render very ugly, improve this maybe by using a custom toast component (in conjunction with error logging maybe) static makeStandardToast(context, toast, err) {
let title = ''
let msg = ''
let variant = ''
switch (toast) { switch (toast) {
case StandardToasts.SUCCESS_CREATE: case StandardToasts.SUCCESS_CREATE:
makeToast(i18n.tc("Success"), i18n.tc("success_creating_resource") + (err_details ? "\n" + err_details : ""), "success") variant = 'success'
title = i18n.tc("Success")
msg = i18n.tc("success_creating_resource")
break break
case StandardToasts.SUCCESS_FETCH: case StandardToasts.SUCCESS_FETCH:
makeToast(i18n.tc("Success"), i18n.tc("success_fetching_resource") + (err_details ? "\n" + err_details : ""), "success") variant = 'success'
title = i18n.tc("Success")
msg = i18n.tc("success_fetching_resource")
break break
case StandardToasts.SUCCESS_UPDATE: case StandardToasts.SUCCESS_UPDATE:
makeToast(i18n.tc("Success"), i18n.tc("success_updating_resource") + (err_details ? "\n" + err_details : ""), "success") variant = 'success'
title = i18n.tc("Success")
msg = i18n.tc("success_updating_resource")
break break
case StandardToasts.SUCCESS_DELETE: case StandardToasts.SUCCESS_DELETE:
makeToast(i18n.tc("Success"), i18n.tc("success_deleting_resource") + (err_details ? "\n" + err_details : ""), "success") variant = 'success'
title = i18n.tc("Success")
msg = i18n.tc("success_deleting_resource")
break break
case StandardToasts.SUCCESS_MOVE: case StandardToasts.SUCCESS_MOVE:
makeToast(i18n.tc("Success"), i18n.tc("success_moving_resource") + (err_details ? "\n" + err_details : ""), "success") variant = 'success'
title = i18n.tc("Success")
msg = i18n.tc("success_moving_resource")
break break
case StandardToasts.SUCCESS_MERGE: case StandardToasts.SUCCESS_MERGE:
makeToast(i18n.tc("Success"), i18n.tc("success_merging_resource") + (err_details ? "\n" + err_details : ""), "success") variant = 'success'
title = i18n.tc("Success")
msg = i18n.tc("success_merging_resource")
break break
case StandardToasts.FAIL_CREATE: case StandardToasts.FAIL_CREATE:
makeToast(i18n.tc("Failure"), i18n.tc("err_creating_resource") + (err_details ? "\n" + err_details : ""), "danger") variant = 'danger'
title = i18n.tc("Failure")
msg = i18n.tc("err_creating_resource")
break break
case StandardToasts.FAIL_FETCH: case StandardToasts.FAIL_FETCH:
makeToast(i18n.tc("Failure"), i18n.tc("err_fetching_resource") + (err_details ? "\n" + err_details : ""), "danger") variant = 'danger'
title = i18n.tc("Failure")
msg = i18n.tc("err_fetching_resource")
break break
case StandardToasts.FAIL_UPDATE: case StandardToasts.FAIL_UPDATE:
makeToast(i18n.tc("Failure"), i18n.tc("err_updating_resource") + (err_details ? "\n" + err_details : ""), "danger") variant = 'danger'
title = i18n.tc("Failure")
msg = i18n.tc("err_updating_resource")
break break
case StandardToasts.FAIL_DELETE: case StandardToasts.FAIL_DELETE:
makeToast(i18n.tc("Failure"), i18n.tc("err_deleting_resource") + (err_details ? "\n" + err_details : ""), "danger") variant = 'danger'
title = i18n.tc("Failure")
msg = i18n.tc("err_deleting_resource")
break break
case StandardToasts.FAIL_DELETE_PROTECTED: case StandardToasts.FAIL_DELETE_PROTECTED:
makeToast(i18n.tc("Protected"), i18n.tc("err_deleting_protected_resource"), "danger") variant = 'danger'
title = i18n.tc("Failure")
msg = i18n.tc("err_deleting_protected_resource")
break break
case StandardToasts.FAIL_MOVE: case StandardToasts.FAIL_MOVE:
makeToast(i18n.tc("Failure"), i18n.tc("err_moving_resource") + (err_details ? "\n" + err_details : ""), "danger") variant = 'danger'
title = i18n.tc("Failure")
msg = i18n.tc("err_moving_resource")
break break
case StandardToasts.FAIL_MERGE: case StandardToasts.FAIL_MERGE:
makeToast(i18n.tc("Failure"), i18n.tc("err_merging_resource") + (err_details ? "\n" + err_details : ""), "danger") variant = 'danger'
title = i18n.tc("Failure")
msg = i18n.tc("err_merging_resource")
break break
} }
let DEBUG = localStorage.getItem("DEBUG") === "True" || false
if (err !== undefined) {
if (DEBUG && err.response.headers['content-type'] === 'application/json' && err.response.status < 500) {
console.log('ERROR ', JSON.stringify(err.response.data))
msg = context.$createElement('div', {}, [
context.$createElement('span', {}, [msg]),
context.$createElement('br', {}, []),
context.$createElement('code', {'class': 'mt-2'}, [JSON.stringify(err.response.data)])
])
}
}
let toaster = new BToast()
toaster.$bvToast.toast(msg, {
title: title,
variant: variant,
toaster: "b-toaster-bottom-right",
solid: true,
})
} }
} }
/*
* Utility function to get random food icon from fontawesome
* */
export const RandomIconMixin = {
name: "RandomIconMixin",
methods: {
getRandomFoodIcon: function () {
return getRandomFoodIcon()
},
},
}
export function getRandomFoodIcon() {
let icons = [
'fas fa-hamburger',
'fas fa-utensils',
'fas fa-apple-alt',
'fas fa-bacon',
'fas fa-bread-slice',
'fas fa-candy-cane',
'fas fa-carrot',
'fas fa-cheese',
'fas fa-cookie',
'fas fa-drumstick-bite',
'fas fa-egg',
'fas fa-fish',
'fas fa-hotdog',
'fas fa-ice-cream',
'fas fa-lemon',
'fas fa-pepper-hot',
'fas fa-pizza-slice',
'fas fa-cookie-bite'
]
return icons[Math.floor(Math.random() * icons.length)];
}
/* /*
* Utility functions to use djangos gettext * Utility functions to use djangos gettext
* */ * */
@@ -167,7 +258,7 @@ export const StaticMixin = {
export function resolveDjangoStatic(param) { export function resolveDjangoStatic(param) {
let url = localStorage.getItem('STATIC_URL') + param let url = localStorage.getItem('STATIC_URL') + param
return url.replace('//','/') //replace // with / in case param started with / which resulted in // after the static base url return url.replace('//', '/') //replace // with / in case param started with / which resulted in // after the static base url
} }
/* /*