Merge branch 'TandoorRecipes:develop' into develop
This commit is contained in:
commit
867c3595ff
@ -221,8 +221,8 @@ class IngredientParser:
|
||||
|
||||
# some people/languages put amount and unit at the end of the ingredient string
|
||||
# if something like this is detected move it to the beginning so the parser can handle it
|
||||
if len(ingredient) < 1000 and re.search(r'^([A-z])+(.)*[1-9](\d)*\s([A-z])+', ingredient):
|
||||
match = re.search(r'[1-9](\d)*\s([A-z])+', ingredient)
|
||||
if len(ingredient) < 1000 and re.search(r'^([^\W\d_])+(.)*[1-9](\d)*\s*([^\W\d_])+', ingredient):
|
||||
match = re.search(r'[1-9](\d)*\s*([^\W\d_])+', ingredient)
|
||||
print(f'reording from {ingredient} to {ingredient[match.start():match.end()] + " " + ingredient.replace(ingredient[match.start():match.end()], "")}')
|
||||
ingredient = ingredient[match.start():match.end()] + ' ' + ingredient.replace(ingredient[match.start():match.end()], '')
|
||||
|
||||
|
@ -66,7 +66,9 @@ def test_ingredient_parser():
|
||||
1.0, 'Lorem', 'ipsum', 'dolor sit amet consetetur sadipscing elitr sed diam nonumy eirmod tempor invidunt ut l Lorem ipsum dolor sit amet consetetur sadipscing elitr sed diam nonumy eirmod tempor invidunt ut l'),
|
||||
"1 LoremipsumdolorsitametconsetetursadipscingelitrseddiamnonumyeirmodtemporinviduntutlLoremipsumdolorsitametconsetetursadipscingelitrseddiamnonumyeirmodtemporinviduntutl": (
|
||||
1.0, None, 'LoremipsumdolorsitametconsetetursadipscingelitrseddiamnonumyeirmodtemporinviduntutlLoremipsumdolorsitametconsetetursadipscingeli',
|
||||
'LoremipsumdolorsitametconsetetursadipscingelitrseddiamnonumyeirmodtemporinviduntutlLoremipsumdolorsitametconsetetursadipscingelitrseddiamnonumyeirmodtemporinviduntutl')
|
||||
'LoremipsumdolorsitametconsetetursadipscingelitrseddiamnonumyeirmodtemporinviduntutlLoremipsumdolorsitametconsetetursadipscingelitrseddiamnonumyeirmodtemporinviduntutl'),
|
||||
"砂糖 50g": (50, "g", "砂糖", ""),
|
||||
"卵 4個": (4, "個", "卵", "")
|
||||
|
||||
}
|
||||
# for German you could say that if an ingredient does not have
|
||||
|
@ -54,7 +54,7 @@ from cookbook.helper.ingredient_parser import IngredientParser
|
||||
from cookbook.helper.permission_helper import (CustomIsAdmin, CustomIsOwner,
|
||||
CustomIsOwnerReadOnly, CustomIsShared,
|
||||
CustomIsSpaceOwner, CustomIsUser, group_required,
|
||||
is_space_owner, switch_user_active_space, above_space_limit, CustomRecipePermission, CustomUserPermission, CustomTokenHasReadWriteScope, CustomTokenHasScope)
|
||||
is_space_owner, switch_user_active_space, above_space_limit, CustomRecipePermission, CustomUserPermission, CustomTokenHasReadWriteScope, CustomTokenHasScope, has_group_permission)
|
||||
from cookbook.helper.recipe_search import RecipeFacet, RecipeSearch
|
||||
from cookbook.helper.recipe_url_import import get_from_youtube_scraper, get_images_from_soup
|
||||
from cookbook.helper.scrapers.scrapers import text_scraper
|
||||
@ -1380,9 +1380,8 @@ def sync_all(request):
|
||||
return redirect('list_recipe_import')
|
||||
|
||||
|
||||
@group_required('user')
|
||||
def share_link(request, pk):
|
||||
if request.space.allow_sharing:
|
||||
if request.space.allow_sharing and has_group_permission(request.user, 'user'):
|
||||
recipe = get_object_or_404(Recipe, pk=pk, space=request.space)
|
||||
link = ShareLink.objects.create(recipe=recipe, created_by=request.user, space=request.space)
|
||||
return JsonResponse({'pk': pk, 'share': link.uuid,
|
||||
|
@ -18,7 +18,7 @@ Lastly you will need to sync with the external path and import recipes you desir
|
||||
There are better ways to do this but they are currently not implemented
|
||||
|
||||
A `Storage Backend` is a remote storage location where files are **read** from.
|
||||
To add a new backend click on `Storage Data` and then on `Storage Backends`.
|
||||
To add a new backend click on `username >> External Recipes >> Manage External Storage >> the + next to Storage Backend List`.
|
||||
There click the plus button.
|
||||
|
||||
The basic configuration is the same for all providers.
|
||||
@ -37,15 +37,23 @@ The basic configuration is the same for all providers.
|
||||
!!! info
|
||||
There is currently no way to upload files through the webinterface. This is a feature that might be added later.
|
||||
|
||||
The local provider does not need any configuration.
|
||||
For the monitor you will need to define a valid path on your host system.
|
||||
The local provider does not need any configuration (username, password, token or URL).
|
||||
For the monitor you will need to define a valid path on your host system. (Path)
|
||||
The Path depends on your setup and can be both relative and absolute.
|
||||
If you use docker the default directory is `/opt/recipes/`.
|
||||
|
||||
!!! warning "Volume"
|
||||
By default no data other than the mediafiles and the database is persisted. If you use the local provider
|
||||
make sure to mount the path you choose to monitor to your host system in order to keep it persistent.
|
||||
|
||||
#### Docker
|
||||
If you use docker the default directory is `/opt/recipes/`.
|
||||
add
|
||||
```
|
||||
- ./externalfiles:/opt/recipes/externalfiles
|
||||
```
|
||||
to your docker-compose.yml file under the `web_recipes >> volumes` section. This will create a folder in your docker directory named `externalfiles` under which you could choose to store external pdfs (you could of course store them anywhere, just change `./externalfiles` to your preferred location).
|
||||
save the docker-compose.yml and restart your docker container.
|
||||
|
||||
### Dropbox
|
||||
|
||||
| Field | Value |
|
||||
@ -66,13 +74,13 @@ If you use docker the default directory is `/opt/recipes/`.
|
||||
| Url | Nextcloud Server URL (e.g. `https://cloud.mydomain.com`) |
|
||||
| Path | (optional) webdav path (e.g. `/remote.php/dav/files/vabene1111`). If no path is supplied `/remote.php/dav/files/` plus your username will be used. |
|
||||
|
||||
## Adding Synced Paths
|
||||
To add a new path from your Storage backend to the sync list, go to `Storage Data >> Configure Sync` and
|
||||
## Adding External Recipes
|
||||
To add a new path from your Storage backend to the sync list, go to `username >> External Recipes` and
|
||||
select the storage backend you want to use.
|
||||
Then enter the path you want to monitor starting at the storage root (e.g. `/Folder/RecipesFolder`) and save it.
|
||||
Then enter the path you want to monitor starting at the storage root (e.g. `/Folder/RecipesFolder`, or `/opt/recipes/externalfiles' in the docker example above) and save it.
|
||||
|
||||
## Syncing Data
|
||||
To sync the recipes app with the storage backends press `Sync now` under `Storage Data >> Configure Sync`.
|
||||
To sync the recipes app with the storage backends press `Sync now` under `username >> External Recipes`
|
||||
|
||||
## Discovered Recipes
|
||||
All files found by the sync can be found under `Manage Data >> Discovered recipes`.
|
||||
|
@ -31,7 +31,7 @@ The filenames consist of `<random uuid4>_<recipe_id>`. In case you screw up real
|
||||
The standard docker build of tandoor uses postgresql as the back end database. This can be backed up using a function called "dumpall". This generates a .SQL file containing a list of commands for a postgresql server to use to rebuild your database. You will also need to back up the media files separately.
|
||||
|
||||
Making a full copy of the docker directory can work as a back up, but only if you know you will be using the same hardware, os, and postgresql version upon restore. If not, then the different version of postgresql won't be compatible with the existing tables.
|
||||
You can back up from docker even when the tandoor container is failing, so long as the postgresql database has started successfully.
|
||||
You can back up from docker even when the tandoor container is failing, so long as the postgresql database has started successfully. When using this backup method, ensure that your recipes have imported successfully. One user reported only the titles and images importing on first try, requiring a second run of the import command.
|
||||
|
||||
the following commands assume that your docker-compose files are in a folder called "docker". replace "docker_db_recipes_1" with the name of your db container. The commands also assume you use a backup name of pgdump.sql. It's a good idea to include a date in this filename, so that successive backups do not get deleted.
|
||||
To back up:
|
||||
@ -47,3 +47,12 @@ cat pgdump.sql | sudo docker exec -i docker_db_recipes_1 psql postgres -U django
|
||||
```
|
||||
This connects to the postgres table instead of the actual dgangodb table, as the import function needs to delete the table, which can't be dropped off you're connected to it.
|
||||
|
||||
## Backup using export and import
|
||||
You can now export recipes from Tandoor using the export function. This method requires a working web interface.
|
||||
1. Click on a recipe
|
||||
2. Click on the three meatballs then export
|
||||
3. Select the all recipes toggle and then export. This should download a zip file.
|
||||
|
||||
Import:
|
||||
Go to Import > from app > tandoor and select the zip file you want to import from.
|
||||
|
||||
|
@ -11,7 +11,6 @@ For all setups using Docker the updating process look something like this
|
||||
2. Pull the latest image using `docker-compose pull`
|
||||
3. Start the container again using `docker-compose up -d`
|
||||
|
||||
|
||||
## Manual
|
||||
|
||||
For all setups using a manual installation updates usually involve downloading the latest source code from GitHub.
|
||||
|
@ -6,16 +6,16 @@ django-cleanup==6.0.0
|
||||
django-crispy-forms==1.14.0
|
||||
django-tables2==2.4.1
|
||||
djangorestframework==3.13.1
|
||||
drf-writable-nested==0.6.4
|
||||
drf-writable-nested==0.7.0
|
||||
django-oauth-toolkit==2.1.0
|
||||
bleach==5.0.1
|
||||
bleach-allowlist==1.0.3
|
||||
gunicorn==20.1.0
|
||||
lxml==4.9.1
|
||||
Markdown==3.3.7
|
||||
Pillow==9.1.1
|
||||
Pillow==9.2.0
|
||||
psycopg2-binary==2.9.3
|
||||
python-dotenv==0.20.0
|
||||
python-dotenv==0.21.0
|
||||
requests==2.28.1
|
||||
six==1.16.0
|
||||
webdavclient3==3.14.6
|
||||
|
@ -18,7 +18,7 @@
|
||||
"babel-core": "^6.26.3",
|
||||
"babel-loader": "^8.2.5",
|
||||
"bootstrap-vue": "^2.21.2",
|
||||
"core-js": "^3.20.3",
|
||||
"core-js": "^3.25.0",
|
||||
"html2pdf.js": "^0.10.1",
|
||||
"lodash": "^4.17.21",
|
||||
"mavon-editor": "^2.10.4",
|
||||
@ -56,7 +56,7 @@
|
||||
"babel-eslint": "^10.1.0",
|
||||
"eslint": "^7.28.0",
|
||||
"eslint-plugin-vue": "^8.7.1",
|
||||
"typescript": "~4.7.2",
|
||||
"typescript": "~4.8.2",
|
||||
"vue-cli-plugin-i18n": "^2.3.1",
|
||||
"webpack-bundle-tracker": "1.5.0",
|
||||
"workbox-expiration": "^6.3.0",
|
||||
|
@ -546,7 +546,7 @@
|
||||
|
||||
<button type="button" class="dropdown-item"
|
||||
v-if="!ingredient.is_header"
|
||||
@click="ingredient.is_header = true">
|
||||
@click="ingredient.is_header = true; ingredient.food=null; ingredient.amount=0; ingredient.unit=null">
|
||||
<i class="fas fa-heading fa-fw"></i>
|
||||
{{ $t("Make_Header") }}
|
||||
</button>
|
||||
|
@ -38,7 +38,7 @@
|
||||
</div>
|
||||
<div class="my-auto mr-1">
|
||||
<span class="text-primary"><b>{{ $t("Preparation") }}</b></span><br/>
|
||||
{{ recipe.working_time }} {{ $t("min") }}
|
||||
{{ working_time }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -50,7 +50,7 @@
|
||||
</div>
|
||||
<div class="my-auto mr-1">
|
||||
<span class="text-primary"><b>{{ $t("Waiting") }}</b></span><br/>
|
||||
{{ recipe.waiting_time }} {{ $t("min") }}
|
||||
{{ waiting_time }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -160,7 +160,7 @@ import "bootstrap-vue/dist/bootstrap-vue.css"
|
||||
import {apiLoadRecipe} from "@/utils/api"
|
||||
|
||||
import RecipeContextMenu from "@/components/RecipeContextMenu"
|
||||
import {ResolveUrlMixin, ToastMixin} from "@/utils/utils"
|
||||
import {ResolveUrlMixin, ToastMixin, calculateHourMinuteSplit} from "@/utils/utils"
|
||||
|
||||
import PdfViewer from "@/components/PdfViewer"
|
||||
import ImageViewer from "@/components/ImageViewer"
|
||||
@ -206,6 +206,10 @@ export default {
|
||||
ingredient_count() {
|
||||
return this.recipe?.steps.map((x) => x.ingredients).flat().length
|
||||
},
|
||||
working_time: function() {
|
||||
return calculateHourMinuteSplit(this.recipe.working_time)},
|
||||
waiting_time: function() {
|
||||
return calculateHourMinuteSplit(this.recipe.waiting_time)},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
|
@ -8,8 +8,8 @@
|
||||
</a>
|
||||
</div>
|
||||
<div class="card-img-overlay w-50 d-flex flex-column justify-content-left float-left text-left pt-2" v-if="recipe.working_time !== 0 || recipe.waiting_time !== 0">
|
||||
<b-badge pill variant="light" class="mt-1 font-weight-normal" v-if="recipe.working_time !== 0"><i class="fa fa-clock"></i> {{ recipe.working_time }} {{ $t("min") }} </b-badge>
|
||||
<b-badge pill variant="secondary" class="mt-1 font-weight-normal" v-if="recipe.waiting_time !== 0"><i class="fa fa-pause"></i> {{ recipe.waiting_time }} {{ $t("min") }} </b-badge>
|
||||
<b-badge pill variant="light" class="mt-1 font-weight-normal" v-if="recipe.working_time !== 0"><i class="fa fa-clock"></i> {{ working_time }} </b-badge>
|
||||
<b-badge pill variant="secondary" class="mt-1 font-weight-normal" v-if="recipe.waiting_time !== 0"><i class="fa fa-pause"></i> {{ waiting_time }} </b-badge>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
@ -59,7 +59,7 @@
|
||||
<script>
|
||||
import RecipeContextMenu from "@/components/RecipeContextMenu"
|
||||
import KeywordsComponent from "@/components/KeywordsComponent"
|
||||
import { resolveDjangoUrl, ResolveUrlMixin } from "@/utils/utils"
|
||||
import { resolveDjangoUrl, ResolveUrlMixin, calculateHourMinuteSplit } from "@/utils/utils"
|
||||
import RecipeRating from "@/components/RecipeRating"
|
||||
import moment from "moment/moment"
|
||||
import Vue from "vue"
|
||||
@ -99,6 +99,10 @@ export default {
|
||||
return this.recipe.image
|
||||
}
|
||||
},
|
||||
working_time: function() {
|
||||
return calculateHourMinuteSplit(this.recipe.working_time)},
|
||||
waiting_time: function() {
|
||||
return calculateHourMinuteSplit(this.recipe.waiting_time)},
|
||||
},
|
||||
methods: {
|
||||
|
||||
|
@ -1,25 +1,34 @@
|
||||
<template>
|
||||
<div>
|
||||
<div class="dropdown d-print-none">
|
||||
<a class="btn shadow-none" href="javascript:void(0);" role="button" id="dropdownMenuLink" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
||||
<a class="btn shadow-none" href="javascript:void(0);" role="button" id="dropdownMenuLink"
|
||||
data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
||||
<i class="fas fa-ellipsis-v fa-lg"></i>
|
||||
</a>
|
||||
|
||||
<div class="dropdown-menu dropdown-menu-right" aria-labelledby="dropdownMenuLink">
|
||||
<a class="dropdown-item" :href="resolveDjangoUrl('edit_recipe', recipe.id)"><i class="fas fa-pencil-alt fa-fw"></i> {{ $t("Edit") }}</a>
|
||||
<a class="dropdown-item" :href="resolveDjangoUrl('edit_recipe', recipe.id)"><i
|
||||
class="fas fa-pencil-alt fa-fw"></i> {{ $t("Edit") }}</a>
|
||||
|
||||
<a class="dropdown-item" :href="resolveDjangoUrl('edit_convert_recipe', recipe.id)" v-if="!recipe.internal"><i class="fas fa-exchange-alt fa-fw"></i> {{ $t("convert_internal") }}</a>
|
||||
<a class="dropdown-item" :href="resolveDjangoUrl('edit_convert_recipe', recipe.id)"
|
||||
v-if="!recipe.internal"><i class="fas fa-exchange-alt fa-fw"></i> {{ $t("convert_internal") }}</a>
|
||||
|
||||
<a href="javascript:void(0);">
|
||||
<button class="dropdown-item" @click="$bvModal.show(`id_modal_add_book_${modal_id}`)"><i class="fas fa-bookmark fa-fw"></i> {{ $t("Manage_Books") }}</button>
|
||||
<button class="dropdown-item" @click="$bvModal.show(`id_modal_add_book_${modal_id}`)"><i
|
||||
class="fas fa-bookmark fa-fw"></i> {{ $t("Manage_Books") }}
|
||||
</button>
|
||||
</a>
|
||||
|
||||
<a class="dropdown-item" v-if="recipe.internal" @click="addToShopping" href="#"> <i class="fas fa-shopping-cart fa-fw"></i> {{ $t("Add_to_Shopping") }} </a>
|
||||
<a class="dropdown-item" v-if="recipe.internal" @click="addToShopping" href="#"> <i
|
||||
class="fas fa-shopping-cart fa-fw"></i> {{ $t("Add_to_Shopping") }} </a>
|
||||
|
||||
<a class="dropdown-item" @click="createMealPlan" href="javascript:void(0);"><i class="fas fa-calendar fa-fw"></i> {{ $t("Add_to_Plan") }} </a>
|
||||
<a class="dropdown-item" @click="createMealPlan" href="javascript:void(0);"><i
|
||||
class="fas fa-calendar fa-fw"></i> {{ $t("Add_to_Plan") }} </a>
|
||||
|
||||
<a href="javascript:void(0);">
|
||||
<button class="dropdown-item" @click="$bvModal.show(`id_modal_cook_log_${modal_id}`)"><i class="fas fa-clipboard-list fa-fw"></i> {{ $t("Log_Cooking") }}</button>
|
||||
<button class="dropdown-item" @click="$bvModal.show(`id_modal_cook_log_${modal_id}`)"><i
|
||||
class="fas fa-clipboard-list fa-fw"></i> {{ $t("Log_Cooking") }}
|
||||
</button>
|
||||
</a>
|
||||
|
||||
<a href="javascript:void(0);">
|
||||
@ -29,10 +38,13 @@
|
||||
</button>
|
||||
</a>
|
||||
<a href="javascript:void(0);">
|
||||
<button class="dropdown-item" @click="copyToNew"><i class="fas fa-copy fa-fw"></i> {{ $t("copy_to_new") }}</button>
|
||||
<button class="dropdown-item" @click="copyToNew"><i class="fas fa-copy fa-fw"></i>
|
||||
{{ $t("copy_to_new") }}
|
||||
</button>
|
||||
</a>
|
||||
|
||||
<a class="dropdown-item" :href="resolveDjangoUrl('view_export') + '?r=' + recipe.id" target="_blank" rel="noopener noreferrer"><i class="fas fa-file-export fa-fw"></i> {{ $t("Export") }}</a>
|
||||
<a class="dropdown-item" :href="resolveDjangoUrl('view_export') + '?r=' + recipe.id" target="_blank"
|
||||
rel="noopener noreferrer"><i class="fas fa-file-export fa-fw"></i> {{ $t("Export") }}</a>
|
||||
|
||||
<a href="javascript:void(0);">
|
||||
<button class="dropdown-item" @click="pinRecipe()">
|
||||
@ -42,13 +54,16 @@
|
||||
</a>
|
||||
|
||||
<a href="javascript:void(0);">
|
||||
<button class="dropdown-item" @click="createShareLink()" v-if="recipe.internal"><i class="fas fa-share-alt fa-fw"></i> {{ $t("Share") }}</button>
|
||||
<button class="dropdown-item" @click="createShareLink()" v-if="recipe.internal"><i
|
||||
class="fas fa-share-alt fa-fw"></i> {{ $t("Share") }}
|
||||
</button>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<cook-log :recipe="recipe" :modal_id="modal_id"></cook-log>
|
||||
<add-recipe-to-book :recipe="recipe" :modal_id="modal_id" :entryEditing_inital_servings="servings_value"></add-recipe-to-book>
|
||||
<add-recipe-to-book :recipe="recipe" :modal_id="modal_id"
|
||||
:entryEditing_inital_servings="servings_value"></add-recipe-to-book>
|
||||
<shopping-modal :recipe="recipe" :servings="servings_value" :modal_id="modal_id" :mealplan="undefined"/>
|
||||
|
||||
<b-modal :id="`modal-share-link_${modal_id}`" v-bind:title="$t('Share')" hide-footer>
|
||||
@ -56,9 +71,16 @@
|
||||
<div class="col col-md-12">
|
||||
<label v-if="recipe_share_link !== undefined">{{ $t("Public share link") }}</label>
|
||||
<input ref="share_link_ref" class="form-control" v-model="recipe_share_link"/>
|
||||
<b-button class="mt-2 mb-3 d-none d-md-inline" variant="secondary" @click="$bvModal.hide(`modal-share-link_${modal_id}`)">{{ $t("Close") }} </b-button>
|
||||
<b-button class="mt-2 mb-3 ml-md-2" variant="primary" @click="copyShareLink()">{{ $t("Copy") }} </b-button>
|
||||
<b-button class="mt-2 mb-3 ml-2 float-right" variant="success" @click="shareIntend()">{{ $t("Share") }} <i class="fa fa-share-alt"></i></b-button>
|
||||
<b-button class="mt-2 mb-3 d-none d-md-inline" variant="secondary"
|
||||
@click="$bvModal.hide(`modal-share-link_${modal_id}`)">{{ $t("Close") }}
|
||||
</b-button>
|
||||
<b-button class="mt-2 mb-3 ml-md-2" variant="primary" @click="copyShareLink()">{{
|
||||
$t("Copy")
|
||||
}}
|
||||
</b-button>
|
||||
<b-button class="mt-2 mb-3 ml-2 float-right" variant="success" @click="shareIntend()">{{
|
||||
$t("Share")
|
||||
}} <i class="fa fa-share-alt"></i></b-button>
|
||||
</div>
|
||||
</div>
|
||||
</b-modal>
|
||||
@ -131,7 +153,8 @@ export default {
|
||||
},
|
||||
watch: {
|
||||
recipe: {
|
||||
handler() {},
|
||||
handler() {
|
||||
},
|
||||
deep: true,
|
||||
},
|
||||
servings: function (newVal) {
|
||||
@ -174,15 +197,15 @@ export default {
|
||||
})
|
||||
},
|
||||
createShareLink: function () {
|
||||
axios
|
||||
.get(resolveDjangoUrl("api_share_link", this.recipe.id))
|
||||
.then((result) => {
|
||||
console.log('create')
|
||||
axios.get(resolveDjangoUrl("api_share_link", this.recipe.id)).then((result) => {
|
||||
console.log('success')
|
||||
this.$bvModal.show(`modal-share-link_${this.modal_id}`)
|
||||
this.recipe_share_link = result.data.link
|
||||
})
|
||||
.catch((err) => {
|
||||
}).catch((err) => {
|
||||
console.log('fail')
|
||||
if (err.response.status === 403) {
|
||||
makeToast(this.$t("Share"), this.$t("Sharing is not enabled for this space."), "danger")
|
||||
makeToast(this.$t("Share"), this.$t("Sharing is not enabled for this space or your user account."), "danger")
|
||||
}
|
||||
})
|
||||
},
|
||||
|
@ -427,5 +427,38 @@
|
||||
"reset_food_inheritance_info": "Zresetuj wszystkie produkty spożywcze do domyślnych dziedziczonych pól i ich wartości nadrzędnych.",
|
||||
"Valid Until": "Ważne do",
|
||||
"show_ingredient_overview": "Wyświetl listę wszystkich składników na początku przepisu.",
|
||||
"Ingredient Overview": "Przegląd składników"
|
||||
"Ingredient Overview": "Przegląd składników",
|
||||
"Decimals": "Ułamki dziesiętne",
|
||||
"Default_Unit": "Jednostka domyślna",
|
||||
"Use_Fractions_Help": "Automatycznie konwertuj ułamki dziesiętne na ułamki zwykłe podczas przeglądania przepisów.",
|
||||
"Language": "Język",
|
||||
"Theme": "Motyw",
|
||||
"plan_share_desc": "Nowe wpisy planu posiłków będą automatycznie udostępniane wybranym użytkownikom.",
|
||||
"Hour": "Godzina",
|
||||
"Hours": "Godziny",
|
||||
"Day": "Dzień",
|
||||
"Days": "Dni",
|
||||
"Second": "Sekunda",
|
||||
"Cosmetic": "Kosmetyk",
|
||||
"API": "API",
|
||||
"Sticky_Nav_Help": "Zawsze pokazuj menu nawigacyjne u góry ekranu.",
|
||||
"Nav_Color": "Kolor nawigacji",
|
||||
"Nav_Color_Help": "Zmień kolor nawigacji.",
|
||||
"Use_Kj": "Użyj kJ zamiast kcal",
|
||||
"Comments_setting": "Pokaż komentarze",
|
||||
"Social_Authentication": "Uwierzytelnianie społecznościowe",
|
||||
"reusable_help_text": "Czy link z zaproszeniem może być używany przez więcej niż jednego użytkownika.",
|
||||
"Private_Recipe": "Prywatny przepis",
|
||||
"Private_Recipe_Help": "Przepis jest widoczny tylko dla Ciebie i dla osób, którym jest udostępniany.",
|
||||
"Use_Fractions": "Użyj ułamków",
|
||||
"Seconds": "Sekundy",
|
||||
"Account": "Konto",
|
||||
"Sticky_Nav": "Przyklejona nawigacja",
|
||||
"Manage_Emails": "Zarządzaj e-mailami",
|
||||
"Change_Password": "Zmień hasło",
|
||||
"Username": "Nazwa użytkownika",
|
||||
"First_name": "Imię",
|
||||
"Last_name": "Nazwisko",
|
||||
"Disabled": "Wyłączone",
|
||||
"Disable": "Wyłączyć"
|
||||
}
|
||||
|
@ -305,6 +305,22 @@ export function roundDecimals(num) {
|
||||
return +(Math.round(num + `e+${decimals}`) + `e-${decimals}`)
|
||||
}
|
||||
|
||||
export function calculateHourMinuteSplit(amount) {
|
||||
if (amount >= 60) {
|
||||
let hours = Math.floor(amount / 60)
|
||||
let minutes = amount - hours * 60
|
||||
let output_text = hours + " h"
|
||||
|
||||
if (minutes > 0){
|
||||
output_text += " " + minutes + " min"
|
||||
}
|
||||
|
||||
return output_text
|
||||
} else {
|
||||
return amount + " min"
|
||||
}
|
||||
}
|
||||
|
||||
const KILOJOULES_PER_CALORIE = 4.18
|
||||
|
||||
export function calculateEnergy(amount, factor) {
|
||||
|
@ -4349,15 +4349,10 @@ core-js@^2.4.0, core-js@^2.5.0:
|
||||
resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.12.tgz#d9333dfa7b065e347cc5682219d6f690859cc2ec"
|
||||
integrity sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==
|
||||
|
||||
core-js@^3.20.3, core-js@^3.6.0, core-js@^3.8.3:
|
||||
version "3.22.7"
|
||||
resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.22.7.tgz#8d6c37f630f6139b8732d10f2c114c3f1d00024f"
|
||||
integrity sha512-Jt8SReuDKVNZnZEzyEQT5eK6T2RRCXkfTq7Lo09kpm+fHjgGewSbNjV+Wt4yZMhPDdzz2x1ulI5z/w4nxpBseg==
|
||||
|
||||
core-js@^3.7.0:
|
||||
version "3.23.0"
|
||||
resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.23.0.tgz#9e33448c8fd3b02ad023d85bd6e85da6335b5cc4"
|
||||
integrity sha512-v2/hZoRcRrvQiBoGsHwmRdr+S4oICKcjA6xb2qjVurin6TpcDC1X2CIDa8rdu/d5n8RT/Sdoos2IlnpQ1rXs5A==
|
||||
core-js@^3.25.0, core-js@^3.6.0, core-js@^3.7.0, core-js@^3.8.3:
|
||||
version "3.25.0"
|
||||
resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.25.0.tgz#be71d9e0dd648ffd70c44a7ec2319d039357eceb"
|
||||
integrity sha512-CVU1xvJEfJGhyCpBrzzzU1kjCfgsGUxhEvwUV2e/cOedYWHdmluamx+knDnmhqALddMG16fZvIqvs9aijsHHaA==
|
||||
|
||||
core-util-is@~1.0.0:
|
||||
version "1.0.3"
|
||||
@ -10822,10 +10817,10 @@ typescript@~4.5.5:
|
||||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.5.5.tgz#d8c953832d28924a9e3d37c73d729c846c5896f3"
|
||||
integrity sha512-TCTIul70LyWe6IJWT8QSYeA54WQe8EjQFU4wY52Fasj5UKx88LNYKCgBEHcOMOrFF1rKGbD8v/xcNWVUq9SymA==
|
||||
|
||||
typescript@~4.7.2:
|
||||
version "4.7.2"
|
||||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.7.2.tgz#1f9aa2ceb9af87cca227813b4310fff0b51593c4"
|
||||
integrity sha512-Mamb1iX2FDUpcTRzltPxgWMKy3fhg0TN378ylbktPGPK/99KbDtMQ4W1hwgsbPAsG3a0xKa1vmw4VKZQbkvz5A==
|
||||
typescript@~4.8.2:
|
||||
version "4.8.2"
|
||||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.8.2.tgz#e3b33d5ccfb5914e4eeab6699cf208adee3fd790"
|
||||
integrity sha512-C0I1UsrrDHo2fYI5oaCGbSejwX4ch+9Y5jTQELvovfmFkK3HHSZJB8MSJcWLmCUBzQBchCrZ9rMRV6GuNrvGtw==
|
||||
|
||||
unbox-primitive@^1.0.2:
|
||||
version "1.0.2"
|
||||
|
Loading…
Reference in New Issue
Block a user