mirror of
https://github.com/TandoorRecipes/recipes.git
synced 2025-12-26 11:49:41 -05:00
Compare commits
55 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b72897b222 | ||
|
|
bca1ebbf99 | ||
|
|
f0342d4568 | ||
|
|
81f62de500 | ||
|
|
f783949a61 | ||
|
|
820fad1b5c | ||
|
|
1169abd942 | ||
|
|
48e175f58f | ||
|
|
5450e18342 | ||
|
|
ea590f8e49 | ||
|
|
13626ca11b | ||
|
|
f53fe1e3c4 | ||
|
|
d177316b47 | ||
|
|
338db1fac2 | ||
|
|
377619473c | ||
|
|
000962c5bb | ||
|
|
9228c1d59f | ||
|
|
27007de7a0 | ||
|
|
29c99b66a1 | ||
|
|
bc179f430d | ||
|
|
58c412ad95 | ||
|
|
4f248afe76 | ||
|
|
f722d24eaa | ||
|
|
723b74509f | ||
|
|
ad4b1393dd | ||
|
|
04bab7072c | ||
|
|
6391cee9eb | ||
|
|
14884fc0d4 | ||
|
|
f2191f79dd | ||
|
|
c2533d9ea2 | ||
|
|
db72fdb1bb | ||
|
|
78252662cb | ||
|
|
4e078bf477 | ||
|
|
2e9e226fe0 | ||
|
|
18cfbd80ab | ||
|
|
4d284b4fff | ||
|
|
b1128dd134 | ||
|
|
3aebf58406 | ||
|
|
f3816a77df | ||
|
|
e4183d79ab | ||
|
|
f4aa1a083f | ||
|
|
ed5508b576 | ||
|
|
040e247487 | ||
|
|
5d28c7b17d | ||
|
|
15b2df07f2 | ||
|
|
7be7c5b954 | ||
|
|
0853a9ec64 | ||
|
|
fa3daee965 | ||
|
|
774c05e76f | ||
|
|
b08c39e284 | ||
|
|
ae036cfa9a | ||
|
|
37628c1735 | ||
|
|
530a6db35c | ||
|
|
2930093da0 | ||
|
|
b7e63a466b |
2
.github/workflows/build-docker.yml
vendored
2
.github/workflows/build-docker.yml
vendored
@@ -21,7 +21,7 @@ jobs:
|
||||
suffix: ""
|
||||
continue-on-error: false
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v5
|
||||
|
||||
- name: Get version number
|
||||
id: get_version
|
||||
|
||||
4
.github/workflows/ci.yml
vendored
4
.github/workflows/ci.yml
vendored
@@ -12,8 +12,8 @@ jobs:
|
||||
python-version: ["3.12"]
|
||||
node-version: ["22"]
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: awalsh128/cache-apt-pkgs-action@v1.5.1
|
||||
- uses: actions/checkout@v5
|
||||
- uses: awalsh128/cache-apt-pkgs-action@v1.5.3
|
||||
with:
|
||||
packages: libsasl2-dev python3-dev libxml2-dev libxmlsec1-dev libxslt-dev libxmlsec1-openssl libxslt-dev libldap2-dev libssl-dev gcc musl-dev postgresql-dev zlib-dev jpeg-dev libwebp-dev openssl-dev libffi-dev cargo openldap-dev python3-dev xmlsec-dev xmlsec build-base g++ curl
|
||||
version: 1.0
|
||||
|
||||
2
.github/workflows/codeql-analysis.yml
vendored
2
.github/workflows/codeql-analysis.yml
vendored
@@ -12,7 +12,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
# We must fetch at least the immediate parents so that if this is
|
||||
# a pull request then we can checkout the head.
|
||||
|
||||
2
.github/workflows/docs.yml
vendored
2
.github/workflows/docs.yml
vendored
@@ -12,7 +12,7 @@ jobs:
|
||||
if: github.repository_owner == 'TandoorRecipes' && ${{ github.event.workflow_run.conclusion == 'success' }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v5
|
||||
- uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: 3.x
|
||||
|
||||
@@ -26,6 +26,7 @@ class ImportExportBase(forms.Form):
|
||||
PAPRIKA = 'PAPRIKA'
|
||||
NEXTCLOUD = 'NEXTCLOUD'
|
||||
MEALIE = 'MEALIE'
|
||||
MEALIE1 = 'MEALIE1'
|
||||
CHOWDOWN = 'CHOWDOWN'
|
||||
SAFFRON = 'SAFFRON'
|
||||
CHEFTAP = 'CHEFTAP'
|
||||
@@ -46,7 +47,7 @@ class ImportExportBase(forms.Form):
|
||||
PDF = 'PDF'
|
||||
GOURMET = 'GOURMET'
|
||||
|
||||
type = forms.ChoiceField(choices=((DEFAULT, _('Default')), (PAPRIKA, 'Paprika'), (NEXTCLOUD, 'Nextcloud Cookbook'), (MEALIE, 'Mealie'), (CHOWDOWN, 'Chowdown'),
|
||||
type = forms.ChoiceField(choices=((DEFAULT, _('Default')), (PAPRIKA, 'Paprika'), (NEXTCLOUD, 'Nextcloud Cookbook'), (MEALIE, 'Mealie'), (MEALIE1, 'Mealie1'), (CHOWDOWN, 'Chowdown'),
|
||||
(SAFFRON, 'Saffron'), (CHEFTAP, 'ChefTap'), (PEPPERPLATE, 'Pepperplate'), (RECETTETEK, 'RecetteTek'), (RECIPESAGE, 'Recipe Sage'),
|
||||
(DOMESTICA, 'Domestica'), (MEALMASTER, 'MealMaster'), (REZKONV, 'RezKonv'), (OPENEATS, 'Openeats'), (RECIPEKEEPER, 'Recipe Keeper'),
|
||||
(PLANTOEAT, 'Plantoeat'), (COOKBOOKAPP, 'CookBookApp'), (COPYMETHAT, 'CopyMeThat'), (PDF, 'PDF'), (MELARECIPES, 'Melarecipes'),
|
||||
@@ -75,6 +76,11 @@ class ImportForm(ImportExportBase):
|
||||
files = MultipleFileField(required=True)
|
||||
duplicates = forms.BooleanField(help_text=_('To prevent duplicates recipes with the same name as existing ones are ignored. Check this box to import everything.'),
|
||||
required=False)
|
||||
meal_plans = forms.BooleanField(required=False)
|
||||
shopping_lists = forms.BooleanField(required=False)
|
||||
nutrition_per_serving = forms.BooleanField(required=False) # some managers (e.g. mealie) do not specify what the nutrition's relate to so we let the user choose
|
||||
|
||||
|
||||
class ExportForm(ImportExportBase):
|
||||
recipes = forms.ModelMultipleChoiceField(widget=MultiSelectWidget, queryset=Recipe.objects.none(), required=False)
|
||||
all = forms.BooleanField(required=False)
|
||||
|
||||
@@ -5,6 +5,7 @@ from django.db.models import Sum
|
||||
from litellm import CustomLogger
|
||||
|
||||
from cookbook.models import AiLog
|
||||
from recipes import settings
|
||||
|
||||
|
||||
def get_monthly_token_usage(space):
|
||||
@@ -61,6 +62,8 @@ class AiCallbackHandler(CustomLogger):
|
||||
remaining_balance = self.space.ai_credits_balance - Decimal(str(credit_cost))
|
||||
if remaining_balance < 0:
|
||||
remaining_balance = 0
|
||||
if settings.HOSTED:
|
||||
self.space.ai_enabled = False
|
||||
|
||||
self.space.ai_credits_balance = remaining_balance
|
||||
credits_from_balance = True
|
||||
|
||||
@@ -3,17 +3,19 @@ import inspect
|
||||
from django.conf import settings
|
||||
from django.contrib import messages
|
||||
from django.contrib.auth.decorators import user_passes_test
|
||||
from django.contrib.auth.models import Group
|
||||
from django.core.cache import cache
|
||||
from django.core.exceptions import ObjectDoesNotExist, ValidationError
|
||||
from django.http import HttpResponseRedirect
|
||||
from django.urls import reverse, reverse_lazy
|
||||
from django.utils.translation import gettext as _
|
||||
from django_scopes import scopes_disabled
|
||||
from oauth2_provider.contrib.rest_framework import TokenHasReadWriteScope, TokenHasScope
|
||||
from oauth2_provider.models import AccessToken
|
||||
from rest_framework import permissions
|
||||
from rest_framework.permissions import SAFE_METHODS
|
||||
|
||||
from cookbook.models import Recipe, ShareLink, UserSpace
|
||||
import random
|
||||
from cookbook.models import Recipe, ShareLink, UserSpace, Space
|
||||
|
||||
|
||||
def get_allowed_groups(groups_required):
|
||||
@@ -330,6 +332,7 @@ class CustomRecipePermission(permissions.BasePermission):
|
||||
return ((has_group_permission(request.user, ['guest']) and request.method in SAFE_METHODS)
|
||||
or has_group_permission(request.user, ['user'])) and obj.space == request.space
|
||||
|
||||
|
||||
class CustomAiProviderPermission(permissions.BasePermission):
|
||||
"""
|
||||
Custom permission class for the AiProvider api endpoint
|
||||
@@ -455,3 +458,36 @@ class IsReadOnlyDRF(permissions.BasePermission):
|
||||
|
||||
def has_permission(self, request, view):
|
||||
return request.method in SAFE_METHODS
|
||||
|
||||
|
||||
class IsCreateDRF(permissions.BasePermission):
|
||||
message = 'You cannot interact with this object, you can only create'
|
||||
|
||||
def has_permission(self, request, view):
|
||||
return request.method == 'POST'
|
||||
|
||||
|
||||
def create_space_for_user(user, name=None):
|
||||
with scopes_disabled():
|
||||
if not name:
|
||||
name = f"{user.username}'s Space"
|
||||
|
||||
if Space.objects.filter(name=name).exists():
|
||||
name = f'{name} #{random.randrange(1, 10 ** 5)}'
|
||||
|
||||
created_space = Space(name=name,
|
||||
created_by=user,
|
||||
max_file_storage_mb=settings.SPACE_DEFAULT_MAX_FILES,
|
||||
max_recipes=settings.SPACE_DEFAULT_MAX_RECIPES,
|
||||
max_users=settings.SPACE_DEFAULT_MAX_USERS,
|
||||
allow_sharing=settings.SPACE_DEFAULT_ALLOW_SHARING,
|
||||
ai_enabled=settings.SPACE_AI_ENABLED,
|
||||
ai_credits_monthly=settings.SPACE_AI_CREDITS_MONTHLY,
|
||||
space_setup_completed=False, )
|
||||
created_space.save()
|
||||
|
||||
UserSpace.objects.filter(user=user).update(active=False)
|
||||
user_space = UserSpace.objects.create(space=created_space, user=user, active=True)
|
||||
user_space.groups.add(Group.objects.filter(name='admin').get())
|
||||
|
||||
return user_space
|
||||
|
||||
@@ -319,10 +319,10 @@ def clean_instruction_string(instruction):
|
||||
.replace("", _('reverse rotation')) \
|
||||
.replace("", _('careful rotation')) \
|
||||
.replace("", _('knead')) \
|
||||
.replace("Andicken ", _('thicken')) \
|
||||
.replace("Erwärmen ", _('warm up')) \
|
||||
.replace("Fermentieren ", _('ferment')) \
|
||||
.replace("Sous-vide ", _("sous-vide"))
|
||||
.replace("", _('thicken')) \
|
||||
.replace("", _('warm up')) \
|
||||
.replace("", _('ferment')) \
|
||||
.replace("", _("sous-vide"))
|
||||
|
||||
|
||||
def parse_instructions(instructions):
|
||||
@@ -403,6 +403,8 @@ def parse_servings_text(servings):
|
||||
|
||||
|
||||
def parse_time(recipe_time):
|
||||
if not recipe_time:
|
||||
return 0
|
||||
if type(recipe_time) not in [int, float]:
|
||||
try:
|
||||
recipe_time = float(re.search(r'\d+', recipe_time).group())
|
||||
|
||||
@@ -1,8 +1,15 @@
|
||||
from django.contrib.auth.models import Group
|
||||
from django.http import HttpResponseRedirect
|
||||
from django.urls import reverse
|
||||
from django_scopes import scope, scopes_disabled
|
||||
from oauth2_provider.contrib.rest_framework import OAuth2Authentication
|
||||
from psycopg2.errors import UniqueViolation
|
||||
from rest_framework.exceptions import AuthenticationFailed
|
||||
|
||||
import random
|
||||
|
||||
from cookbook.helper.permission_helper import create_space_for_user
|
||||
from cookbook.models import Space, UserSpace
|
||||
from cookbook.views import views
|
||||
from recipes import settings
|
||||
|
||||
@@ -34,16 +41,28 @@ class ScopeMiddleware:
|
||||
if request.path.startswith(prefix + '/switch-space/'):
|
||||
return self.get_response(request)
|
||||
|
||||
with scopes_disabled():
|
||||
if request.user.userspace_set.count() == 0 and not reverse('account_logout') in request.path:
|
||||
return views.space_overview(request)
|
||||
if request.path.startswith(prefix + '/invite/'):
|
||||
return self.get_response(request)
|
||||
|
||||
# get active user space, if for some reason more than one space is active select first (group permission checks will fail, this is not intended at this point)
|
||||
user_space = request.user.userspace_set.filter(active=True).first()
|
||||
|
||||
if not user_space:
|
||||
return views.space_overview(request)
|
||||
if not user_space and request.user.userspace_set.count() > 0:
|
||||
# if the users has a userspace but nothing is active, activate the first one
|
||||
user_space = request.user.userspace_set.first()
|
||||
if user_space:
|
||||
user_space.active = True
|
||||
user_space.save()
|
||||
|
||||
if not user_space:
|
||||
if 'signup_token' in request.session:
|
||||
# if user is authenticated, has no space but a signup token (InviteLink) is present, redirect to invite link logic
|
||||
return HttpResponseRedirect(reverse('view_invite', args=[request.session.pop('signup_token', '')]))
|
||||
else:
|
||||
# if user does not yet have a space create one for him
|
||||
user_space = create_space_for_user(request.user)
|
||||
|
||||
# TODO remove the need for this view
|
||||
if user_space.groups.count() == 0 and not reverse('account_logout') in request.path:
|
||||
return views.no_groups(request)
|
||||
|
||||
|
||||
@@ -26,6 +26,12 @@ class Integration:
|
||||
files = None
|
||||
export_type = None
|
||||
ignored_recipes = []
|
||||
import_log = None
|
||||
import_duplicates = False
|
||||
|
||||
import_meal_plans = True
|
||||
import_shopping_lists = True
|
||||
nutrition_per_serving = False
|
||||
|
||||
def __init__(self, request, export_type):
|
||||
"""
|
||||
@@ -102,7 +108,7 @@ class Integration:
|
||||
"""
|
||||
return True
|
||||
|
||||
def do_import(self, files, il, import_duplicates):
|
||||
def do_import(self, files, il, import_duplicates, meal_plans=True, shopping_lists=True, nutrition_per_serving=False):
|
||||
"""
|
||||
Imports given files
|
||||
:param import_duplicates: if true duplicates are imported as well
|
||||
@@ -111,6 +117,12 @@ class Integration:
|
||||
:return: HttpResponseRedirect to the recipe search showing all imported recipes
|
||||
"""
|
||||
with scope(space=self.request.space):
|
||||
self.import_log = il
|
||||
self.import_duplicates = import_duplicates
|
||||
|
||||
self.import_meal_plans = meal_plans
|
||||
self.import_shopping_lists = shopping_lists
|
||||
self.nutrition_per_serving = nutrition_per_serving
|
||||
|
||||
try:
|
||||
self.files = files
|
||||
@@ -166,20 +178,24 @@ class Integration:
|
||||
il.total_recipes = len(new_file_list)
|
||||
file_list = new_file_list
|
||||
|
||||
for z in file_list:
|
||||
try:
|
||||
if not hasattr(z, 'filename') or isinstance(z, Tag):
|
||||
recipe = self.get_recipe_from_file(z)
|
||||
else:
|
||||
recipe = self.get_recipe_from_file(BytesIO(import_zip.read(z.filename)))
|
||||
recipe.keywords.add(self.keyword)
|
||||
il.msg += self.get_recipe_processed_msg(recipe)
|
||||
self.handle_duplicates(recipe, import_duplicates)
|
||||
il.imported_recipes += 1
|
||||
il.save()
|
||||
except Exception as e:
|
||||
traceback.print_exc()
|
||||
self.handle_exception(e, log=il, message=f'-------------------- \nERROR \n{e}\n--------------------\n')
|
||||
if isinstance(self, cookbook.integration.mealie1.Mealie1):
|
||||
# since the mealie 1.0 export is a backup and not a classic recipe export we treat it a bit differently
|
||||
recipes = self.get_recipe_from_file(import_zip)
|
||||
else:
|
||||
for z in file_list:
|
||||
try:
|
||||
if not hasattr(z, 'filename') or isinstance(z, Tag):
|
||||
recipe = self.get_recipe_from_file(z)
|
||||
else:
|
||||
recipe = self.get_recipe_from_file(BytesIO(import_zip.read(z.filename)))
|
||||
recipe.keywords.add(self.keyword)
|
||||
il.msg += self.get_recipe_processed_msg(recipe)
|
||||
self.handle_duplicates(recipe, import_duplicates)
|
||||
il.imported_recipes += 1
|
||||
il.save()
|
||||
except Exception as e:
|
||||
traceback.print_exc()
|
||||
self.handle_exception(e, log=il, message=f'-------------------- \nERROR \n{e}\n--------------------\n')
|
||||
import_zip.close()
|
||||
elif '.json' in f['name'] or '.xml' in f['name'] or '.txt' in f['name'] or '.mmf' in f['name'] or '.rk' in f['name'] or '.melarecipe' in f['name']:
|
||||
data_list = self.split_recipe_file(f['file'])
|
||||
|
||||
342
cookbook/integration/mealie1.py
Normal file
342
cookbook/integration/mealie1.py
Normal file
@@ -0,0 +1,342 @@
|
||||
import json
|
||||
import re
|
||||
import traceback
|
||||
import uuid
|
||||
from decimal import Decimal
|
||||
from io import BytesIO
|
||||
from zipfile import ZipFile
|
||||
from gettext import gettext as _
|
||||
|
||||
from django.db import transaction
|
||||
|
||||
from cookbook.helper import ingredient_parser
|
||||
from cookbook.helper.image_processing import get_filetype
|
||||
from cookbook.helper.ingredient_parser import IngredientParser
|
||||
from cookbook.helper.recipe_url_import import parse_servings, parse_servings_text, parse_time
|
||||
from cookbook.integration.integration import Integration
|
||||
from cookbook.models import Ingredient, Keyword, Recipe, Step, Food, Unit, SupermarketCategory, PropertyType, Property, MealType, MealPlan, CookLog, ShoppingListEntry
|
||||
|
||||
|
||||
class Mealie1(Integration):
|
||||
"""
|
||||
integration for mealie past version 1.0
|
||||
"""
|
||||
|
||||
def get_recipe_from_file(self, file):
|
||||
mealie_database = json.loads(BytesIO(file.read('database.json')).getvalue().decode("utf-8"))
|
||||
self.import_log.total_recipes = len(mealie_database['recipes'])
|
||||
self.import_log.msg += f"Importing {len(mealie_database["categories"]) + len(mealie_database["tags"])} tags and categories as keywords...\n"
|
||||
self.import_log.save()
|
||||
|
||||
keywords_categories_dict = {}
|
||||
for c in mealie_database['categories']:
|
||||
if keyword := Keyword.objects.filter(name=c['name'], space=self.request.space).first():
|
||||
keywords_categories_dict[c['id']] = keyword.pk
|
||||
else:
|
||||
keyword = Keyword.objects.create(name=c['name'], space=self.request.space)
|
||||
keywords_categories_dict[c['id']] = keyword.pk
|
||||
|
||||
keywords_tags_dict = {}
|
||||
for t in mealie_database['tags']:
|
||||
if keyword := Keyword.objects.filter(name=t['name'], space=self.request.space).first():
|
||||
keywords_tags_dict[t['id']] = keyword.pk
|
||||
else:
|
||||
keyword = Keyword.objects.create(name=t['name'], space=self.request.space)
|
||||
keywords_tags_dict[t['id']] = keyword.pk
|
||||
|
||||
self.import_log.msg += f"Importing {len(mealie_database["multi_purpose_labels"])} multi purpose labels as supermarket categories...\n"
|
||||
self.import_log.save()
|
||||
|
||||
supermarket_categories_dict = {}
|
||||
for m in mealie_database['multi_purpose_labels']:
|
||||
if supermarket_category := SupermarketCategory.objects.filter(name=m['name'], space=self.request.space).first():
|
||||
supermarket_categories_dict[m['id']] = supermarket_category.pk
|
||||
else:
|
||||
supermarket_category = SupermarketCategory.objects.create(name=m['name'], space=self.request.space)
|
||||
supermarket_categories_dict[m['id']] = supermarket_category.pk
|
||||
|
||||
self.import_log.msg += f"Importing {len(mealie_database["ingredient_foods"])} foods...\n"
|
||||
self.import_log.save()
|
||||
|
||||
foods_dict = {}
|
||||
for f in mealie_database['ingredient_foods']:
|
||||
if food := Food.objects.filter(name=f['name'], space=self.request.space).first():
|
||||
foods_dict[f['id']] = food.pk
|
||||
else:
|
||||
food = {'name': f['name'],
|
||||
'plural_name': f['plural_name'],
|
||||
'description': f['description'],
|
||||
'space': self.request.space}
|
||||
|
||||
if f['label_id'] and f['label_id'] in supermarket_categories_dict:
|
||||
food['supermarket_category_id'] = supermarket_categories_dict[f['label_id']]
|
||||
|
||||
food = Food.objects.create(**food)
|
||||
if f['on_hand']:
|
||||
food.onhand_users.add(self.request.user)
|
||||
foods_dict[f['id']] = food.pk
|
||||
|
||||
self.import_log.msg += f"Importing {len(mealie_database["ingredient_units"])} units...\n"
|
||||
self.import_log.save()
|
||||
|
||||
units_dict = {}
|
||||
for u in mealie_database['ingredient_units']:
|
||||
if unit := Unit.objects.filter(name=u['name'], space=self.request.space).first():
|
||||
units_dict[u['id']] = unit.pk
|
||||
else:
|
||||
unit = Unit.objects.create(name=u['name'], plural_name=u['plural_name'], description=u['description'], space=self.request.space)
|
||||
units_dict[u['id']] = unit.pk
|
||||
|
||||
recipes_dict = {}
|
||||
recipe_property_factor_dict = {}
|
||||
recipes = []
|
||||
recipe_keyword_relation = []
|
||||
for r in mealie_database['recipes']:
|
||||
if Recipe.objects.filter(space=self.request.space, name=r['name']).exists() and not self.import_duplicates:
|
||||
self.import_log.msg += f"Ignoring {r['name']} because a recipe with this name already exists.\n"
|
||||
self.import_log.save()
|
||||
else:
|
||||
recipe = Recipe.objects.create(
|
||||
waiting_time=parse_time(r['perform_time']),
|
||||
working_time=parse_time(r['prep_time']),
|
||||
description=r['description'][:512],
|
||||
name=r['name'],
|
||||
source_url=r['org_url'],
|
||||
servings=r['recipe_servings'] if r['recipe_servings'] and r['recipe_servings'] != 0 else 1,
|
||||
servings_text=r['recipe_yield'].strip() if r['recipe_yield'] else "",
|
||||
internal=True,
|
||||
created_at=r['created_at'],
|
||||
space=self.request.space,
|
||||
created_by=self.request.user,
|
||||
)
|
||||
|
||||
if not self.nutrition_per_serving:
|
||||
recipe_property_factor_dict[r['id']] = recipe.servings
|
||||
|
||||
self.import_log.msg += self.get_recipe_processed_msg(recipe)
|
||||
self.import_log.imported_recipes += 1
|
||||
self.import_log.save()
|
||||
|
||||
recipes.append(recipe)
|
||||
recipes_dict[r['id']] = recipe.pk
|
||||
recipe_keyword_relation.append(Recipe.keywords.through(recipe_id=recipe.pk, keyword_id=self.keyword.pk))
|
||||
|
||||
Recipe.keywords.through.objects.bulk_create(recipe_keyword_relation, ignore_conflicts=True)
|
||||
|
||||
self.import_log.msg += f"Importing {len(mealie_database["recipe_instructions"])} instructions...\n"
|
||||
self.import_log.save()
|
||||
|
||||
steps_relation = []
|
||||
first_step_of_recipe_dict = {}
|
||||
for s in mealie_database['recipe_instructions']:
|
||||
if s['recipe_id'] in recipes_dict:
|
||||
step = Step.objects.create(instruction=(s['text'] if s['text'] else "") + (f" \n {s['summary']}" if s['summary'] else ""),
|
||||
order=s['position'],
|
||||
name=s['title'],
|
||||
space=self.request.space)
|
||||
steps_relation.append(Recipe.steps.through(recipe_id=recipes_dict[s['recipe_id']], step_id=step.pk))
|
||||
if s['recipe_id'] not in first_step_of_recipe_dict:
|
||||
first_step_of_recipe_dict[s['recipe_id']] = step.pk
|
||||
|
||||
for n in mealie_database['notes']:
|
||||
if n['recipe_id'] in recipes_dict:
|
||||
step = Step.objects.create(instruction=n['text'],
|
||||
name=n['title'],
|
||||
order=100,
|
||||
space=self.request.space)
|
||||
steps_relation.append(Recipe.steps.through(recipe_id=recipes_dict[n['recipe_id']], step_id=step.pk))
|
||||
|
||||
Recipe.steps.through.objects.bulk_create(steps_relation)
|
||||
|
||||
ingredient_parser = IngredientParser(self.request, True)
|
||||
|
||||
self.import_log.msg += f"Importing {len(mealie_database["recipes_ingredients"])} ingredients...\n"
|
||||
self.import_log.save()
|
||||
|
||||
ingredients_relation = []
|
||||
for i in mealie_database['recipes_ingredients']:
|
||||
if i['recipe_id'] in recipes_dict:
|
||||
if i['title']:
|
||||
title_ingredient = Ingredient.objects.create(
|
||||
note=i['title'],
|
||||
is_header=True,
|
||||
space=self.request.space,
|
||||
)
|
||||
ingredients_relation.append(Step.ingredients.through(step_id=first_step_of_recipe_dict[i['recipe_id']], ingredient_id=title_ingredient.pk))
|
||||
if i['food_id']:
|
||||
ingredient = Ingredient.objects.create(
|
||||
food_id=foods_dict[i['food_id']] if i['food_id'] in foods_dict else None,
|
||||
unit_id=units_dict[i['unit_id']] if i['unit_id'] in units_dict else None,
|
||||
original_text=i['original_text'],
|
||||
order=i['position'],
|
||||
amount=i['quantity'],
|
||||
note=i['note'],
|
||||
space=self.request.space,
|
||||
)
|
||||
ingredients_relation.append(Step.ingredients.through(step_id=first_step_of_recipe_dict[i['recipe_id']], ingredient_id=ingredient.pk))
|
||||
elif i['note'].strip():
|
||||
amount, unit, food, note = ingredient_parser.parse(i['note'].strip())
|
||||
f = ingredient_parser.get_food(food)
|
||||
u = ingredient_parser.get_unit(unit)
|
||||
ingredient = Ingredient.objects.create(
|
||||
food=f,
|
||||
unit=u,
|
||||
amount=amount,
|
||||
note=note,
|
||||
original_text=i['original_text'],
|
||||
space=self.request.space,
|
||||
)
|
||||
ingredients_relation.append(Step.ingredients.through(step_id=first_step_of_recipe_dict[i['recipe_id']], ingredient_id=ingredient.pk))
|
||||
Step.ingredients.through.objects.bulk_create(ingredients_relation)
|
||||
|
||||
self.import_log.msg += f"Importing {len(mealie_database["recipes_to_categories"]) + len(mealie_database["recipes_to_tags"])} category and keyword relations...\n"
|
||||
self.import_log.save()
|
||||
|
||||
recipe_keyword_relation = []
|
||||
for rC in mealie_database['recipes_to_categories']:
|
||||
if rC['recipe_id'] in recipes_dict:
|
||||
recipe_keyword_relation.append(Recipe.keywords.through(recipe_id=recipes_dict[rC['recipe_id']], keyword_id=keywords_categories_dict[rC['category_id']]))
|
||||
|
||||
for rT in mealie_database['recipes_to_tags']:
|
||||
if rT['recipe_id'] in recipes_dict:
|
||||
recipe_keyword_relation.append(Recipe.keywords.through(recipe_id=recipes_dict[rT['recipe_id']], keyword_id=keywords_tags_dict[rT['tag_id']]))
|
||||
|
||||
Recipe.keywords.through.objects.bulk_create(recipe_keyword_relation, ignore_conflicts=True)
|
||||
|
||||
self.import_log.msg += f"Importing {len(mealie_database["recipe_nutrition"])} properties...\n"
|
||||
self.import_log.save()
|
||||
|
||||
property_types_dict = {
|
||||
'calories': PropertyType.objects.get_or_create(name=_('Calories'), space=self.request.space, defaults={'unit': 'kcal', 'fdc_id': 1008})[0],
|
||||
'carbohydrate_content': PropertyType.objects.get_or_create(name=_('Carbohydrates'), space=self.request.space, defaults={'unit': 'g', 'fdc_id': 1005})[0],
|
||||
'cholesterol_content': PropertyType.objects.get_or_create(name=_('Cholesterol'), space=self.request.space, defaults={'unit': 'mg', 'fdc_id': 1253})[0],
|
||||
'fat_content': PropertyType.objects.get_or_create(name=_('Fat'), space=self.request.space, defaults={'unit': 'g', 'fdc_id': 1004})[0],
|
||||
'fiber_content': PropertyType.objects.get_or_create(name=_('Fiber'), space=self.request.space, defaults={'unit': 'g', 'fdc_id': 1079})[0],
|
||||
'protein_content': PropertyType.objects.get_or_create(name=_('Protein'), space=self.request.space, defaults={'unit': 'g', 'fdc_id': 1003})[0],
|
||||
'saturated_fat_content': PropertyType.objects.get_or_create(name=_('Saturated Fat'), space=self.request.space, defaults={'unit': 'g', 'fdc_id': 1258})[0],
|
||||
'sodium_content': PropertyType.objects.get_or_create(name=_('Sodium'), space=self.request.space, defaults={'unit': 'mg', 'fdc_id': 1093})[0],
|
||||
'sugar_content': PropertyType.objects.get_or_create(name=_('Sugar'), space=self.request.space, defaults={'unit': 'g', 'fdc_id': 1063})[0],
|
||||
'trans_fat_content': PropertyType.objects.get_or_create(name=_('Trans Fat'), space=self.request.space, defaults={'unit': 'g', 'fdc_id': 1257})[0],
|
||||
'unsaturated_fat_content': PropertyType.objects.get_or_create(name=_('Unsaturated Fat'), space=self.request.space, defaults={'unit': 'g'})[0],
|
||||
}
|
||||
|
||||
with transaction.atomic():
|
||||
recipe_properties_relation = []
|
||||
properties_relation = []
|
||||
for r in mealie_database['recipe_nutrition']:
|
||||
if r['recipe_id'] in recipes_dict:
|
||||
for key in property_types_dict:
|
||||
if r[key]:
|
||||
properties_relation.append(
|
||||
Property(property_type_id=property_types_dict[key].pk,
|
||||
property_amount=Decimal(str(r[key])) / (
|
||||
Decimal(str(recipe_property_factor_dict[r['recipe_id']])) if r['recipe_id'] in recipe_property_factor_dict else 1),
|
||||
open_data_food_slug=r['recipe_id'],
|
||||
space=self.request.space))
|
||||
properties = Property.objects.bulk_create(properties_relation)
|
||||
property_ids = []
|
||||
for p in properties:
|
||||
recipe_properties_relation.append(Recipe.properties.through(recipe_id=recipes_dict[p.open_data_food_slug], property_id=p.pk))
|
||||
property_ids.append(p.pk)
|
||||
Recipe.properties.through.objects.bulk_create(recipe_properties_relation, ignore_conflicts=True)
|
||||
Property.objects.filter(id__in=property_ids).update(open_data_food_slug=None)
|
||||
|
||||
# delete unused property types
|
||||
for pT in property_types_dict:
|
||||
try:
|
||||
property_types_dict[pT].delete()
|
||||
except:
|
||||
pass
|
||||
|
||||
self.import_log.msg += f"Importing {len(mealie_database["recipe_comments"]) + len(mealie_database["recipe_timeline_events"])} comments and cook logs...\n"
|
||||
self.import_log.save()
|
||||
|
||||
cook_log_list = []
|
||||
for c in mealie_database['recipe_comments']:
|
||||
if c['recipe_id'] in recipes_dict:
|
||||
cook_log_list.append(CookLog(
|
||||
recipe_id=recipes_dict[c['recipe_id']],
|
||||
comment=c['text'],
|
||||
created_at=c['created_at'],
|
||||
created_by=self.request.user,
|
||||
space=self.request.space,
|
||||
))
|
||||
|
||||
for c in mealie_database['recipe_timeline_events']:
|
||||
if c['recipe_id'] in recipes_dict:
|
||||
if c['event_type'] == 'comment':
|
||||
cook_log_list.append(CookLog(
|
||||
recipe_id=recipes_dict[c['recipe_id']],
|
||||
comment=c['message'],
|
||||
created_at=c['created_at'],
|
||||
created_by=self.request.user,
|
||||
space=self.request.space,
|
||||
))
|
||||
|
||||
CookLog.objects.bulk_create(cook_log_list)
|
||||
|
||||
if self.import_meal_plans:
|
||||
self.import_log.msg += f"Importing {len(mealie_database["group_meal_plans"])} meal plans...\n"
|
||||
self.import_log.save()
|
||||
|
||||
meal_types_dict = {}
|
||||
meal_plans = []
|
||||
for m in mealie_database['group_meal_plans']:
|
||||
if m['recipe_id'] in recipes_dict:
|
||||
if not m['entry_type'] in meal_types_dict:
|
||||
meal_type = MealType.objects.get_or_create(name=m['entry_type'], created_by=self.request.user, space=self.request.space)[0]
|
||||
meal_types_dict[m['entry_type']] = meal_type.pk
|
||||
meal_plans.append(MealPlan(
|
||||
recipe_id=recipes_dict[m['recipe_id']] if m['recipe_id'] else None,
|
||||
title=m['title'] if m['title'] else "",
|
||||
note=m['text'] if m['text'] else "",
|
||||
from_date=m['date'],
|
||||
to_date=m['date'],
|
||||
meal_type_id=meal_types_dict[m['entry_type']],
|
||||
created_by=self.request.user,
|
||||
space=self.request.space,
|
||||
))
|
||||
|
||||
MealPlan.objects.bulk_create(meal_plans)
|
||||
|
||||
if self.import_shopping_lists:
|
||||
self.import_log.msg += f"Importing {len(mealie_database["shopping_list_items"])} shopping list items...\n"
|
||||
self.import_log.save()
|
||||
|
||||
shopping_list_items = []
|
||||
for sli in mealie_database['shopping_list_items']:
|
||||
if not sli['checked']:
|
||||
if sli['food_id']:
|
||||
shopping_list_items.append(ShoppingListEntry(
|
||||
amount=sli['quantity'],
|
||||
unit_id=units_dict[sli['unit_id']] if sli['unit_id'] else None,
|
||||
food_id=foods_dict[sli['food_id']] if sli['food_id'] else None,
|
||||
created_by=self.request.user,
|
||||
space=self.request.space,
|
||||
))
|
||||
elif not sli['food_id'] and sli['note'].strip():
|
||||
amount, unit, food, note = ingredient_parser.parse(sli['note'].strip())
|
||||
f = ingredient_parser.get_food(food)
|
||||
u = ingredient_parser.get_unit(unit)
|
||||
shopping_list_items.append(ShoppingListEntry(
|
||||
amount=amount,
|
||||
unit=u,
|
||||
food=f,
|
||||
created_by=self.request.user,
|
||||
space=self.request.space,
|
||||
))
|
||||
ShoppingListEntry.objects.bulk_create(shopping_list_items)
|
||||
|
||||
self.import_log.msg += f"Importing Images. This might take some time ...\n"
|
||||
self.import_log.save()
|
||||
for r in mealie_database['recipes']:
|
||||
try:
|
||||
if recipe := Recipe.objects.filter(pk=recipes_dict[r['id']]).first():
|
||||
self.import_recipe_image(recipe, BytesIO(file.read(f'data/recipes/{str(uuid.UUID(str(r['id'])))}/images/original.webp')), filetype='.webp')
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
return recipes
|
||||
|
||||
def get_file_from_recipe(self, recipe):
|
||||
raise NotImplementedError('Method not implemented in storage integration')
|
||||
File diff suppressed because it is too large
Load Diff
18
cookbook/migrations/0228_space_space_setup_completed.py
Normal file
18
cookbook/migrations/0228_space_space_setup_completed.py
Normal file
@@ -0,0 +1,18 @@
|
||||
# Generated by Django 5.2.6 on 2025-09-10 20:11
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('cookbook', '0001_squashed_0227_space_ai_default_provider_and_more'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='space',
|
||||
name='space_setup_completed',
|
||||
field=models.BooleanField(default=True),
|
||||
),
|
||||
]
|
||||
@@ -329,6 +329,8 @@ class Space(ExportModelOperationsMixin('space'), models.Model):
|
||||
demo = models.BooleanField(default=False)
|
||||
food_inherit = models.ManyToManyField(FoodInheritField, blank=True)
|
||||
|
||||
space_setup_completed = models.BooleanField(default=True)
|
||||
|
||||
ai_enabled = models.BooleanField(default=True)
|
||||
ai_credits_monthly = models.IntegerField(default=100)
|
||||
ai_credits_balance = models.DecimalField(default=0, max_digits=16, decimal_places=4)
|
||||
|
||||
@@ -26,7 +26,7 @@ from cookbook.helper.CustomStorageClass import CachedS3Boto3Storage
|
||||
from cookbook.helper.HelperFunctions import str2bool
|
||||
from cookbook.helper.ai_helper import get_monthly_token_usage
|
||||
from cookbook.helper.image_processing import is_file_type_allowed
|
||||
from cookbook.helper.permission_helper import above_space_limit
|
||||
from cookbook.helper.permission_helper import above_space_limit, create_space_for_user
|
||||
from cookbook.helper.property_helper import FoodPropertyHelper
|
||||
from cookbook.helper.shopping_helper import RecipeShoppingEditor
|
||||
from cookbook.helper.unit_conversion_helper import UnitConversionHelper
|
||||
@@ -367,12 +367,12 @@ class AiLogSerializer(serializers.ModelSerializer):
|
||||
|
||||
class SpaceSerializer(WritableNestedModelSerializer):
|
||||
created_by = UserSerializer(read_only=True)
|
||||
user_count = serializers.SerializerMethodField('get_user_count')
|
||||
recipe_count = serializers.SerializerMethodField('get_recipe_count')
|
||||
file_size_mb = serializers.SerializerMethodField('get_file_size_mb')
|
||||
ai_monthly_credits_used = serializers.SerializerMethodField('get_ai_monthly_credits_used')
|
||||
user_count = serializers.SerializerMethodField('get_user_count', read_only=True)
|
||||
recipe_count = serializers.SerializerMethodField('get_recipe_count', read_only=True)
|
||||
file_size_mb = serializers.SerializerMethodField('get_file_size_mb', read_only=True)
|
||||
ai_monthly_credits_used = serializers.SerializerMethodField('get_ai_monthly_credits_used', read_only=True)
|
||||
ai_default_provider = AiProviderSerializer(required=False, allow_null=True)
|
||||
food_inherit = FoodInheritFieldSerializer(many=True)
|
||||
food_inherit = FoodInheritFieldSerializer(many=True, required=False)
|
||||
image = UserFileViewSerializer(required=False, many=False, allow_null=True)
|
||||
nav_logo = UserFileViewSerializer(required=False, many=False, allow_null=True)
|
||||
custom_space_theme = UserFileViewSerializer(required=False, many=False, allow_null=True)
|
||||
@@ -404,9 +404,26 @@ class SpaceSerializer(WritableNestedModelSerializer):
|
||||
return 0
|
||||
|
||||
def create(self, validated_data):
|
||||
raise ValidationError('Cannot create using this endpoint')
|
||||
if Space.objects.filter(created_by=self.context['request'].user).count() >= self.context['request'].user.userpreference.max_owned_spaces:
|
||||
raise serializers.ValidationError(
|
||||
_('You have the reached the maximum amount of spaces that can be owned by you.') + f' ({self.context['request'].user.userpreference.max_owned_spaces})')
|
||||
|
||||
name = None
|
||||
if 'name' in validated_data:
|
||||
name = validated_data['name']
|
||||
user_space = create_space_for_user(self.context['request'].user, name)
|
||||
return user_space.space
|
||||
|
||||
def update(self, instance, validated_data):
|
||||
validated_data = self.filter_superuser_parameters(validated_data)
|
||||
|
||||
if 'name' in validated_data:
|
||||
if Space.objects.filter(Q(name=validated_data['name']), ~Q(pk=instance.pk)).exists():
|
||||
raise ValidationError(_('Space Name must be unique.'))
|
||||
|
||||
return super().update(instance, validated_data)
|
||||
|
||||
def filter_superuser_parameters(self, validated_data):
|
||||
if 'ai_enabled' in validated_data and not self.context['request'].user.is_superuser:
|
||||
del validated_data['ai_enabled']
|
||||
|
||||
@@ -416,7 +433,7 @@ class SpaceSerializer(WritableNestedModelSerializer):
|
||||
if 'ai_credits_balance' in validated_data and not self.context['request'].user.is_superuser:
|
||||
del validated_data['ai_credits_balance']
|
||||
|
||||
return super().update(instance, validated_data)
|
||||
return validated_data
|
||||
|
||||
class Meta:
|
||||
model = Space
|
||||
@@ -425,7 +442,7 @@ class SpaceSerializer(WritableNestedModelSerializer):
|
||||
'allow_sharing', 'demo', 'food_inherit', 'user_count', 'recipe_count', 'file_size_mb',
|
||||
'image', 'nav_logo', 'space_theme', 'custom_space_theme', 'nav_bg_color', 'nav_text_color',
|
||||
'logo_color_32', 'logo_color_128', 'logo_color_144', 'logo_color_180', 'logo_color_192', 'logo_color_512', 'logo_color_svg', 'ai_credits_monthly',
|
||||
'ai_credits_balance', 'ai_monthly_credits_used', 'ai_enabled', 'ai_default_provider')
|
||||
'ai_credits_balance', 'ai_monthly_credits_used', 'ai_enabled', 'ai_default_provider', 'space_setup_completed')
|
||||
read_only_fields = (
|
||||
'id', 'created_by', 'created_at', 'max_recipes', 'max_file_storage_mb', 'max_users', 'allow_sharing',
|
||||
'demo', 'ai_monthly_credits_used')
|
||||
|
||||
@@ -41,6 +41,12 @@ def test_list_space(obj_1, obj_2, u1_s1, u1_s2, space_2):
|
||||
assert json.loads(u1_s1.get(reverse(LIST_URL)).content)['count'] == 1
|
||||
assert json.loads(u1_s2.get(reverse(LIST_URL)).content)['count'] == 2
|
||||
|
||||
obj_1.space = None
|
||||
obj_1.save()
|
||||
|
||||
assert json.loads(u1_s1.get(reverse(LIST_URL)).content)['count'] == 2
|
||||
assert json.loads(u1_s2.get(reverse(LIST_URL)).content)['count'] == 2
|
||||
|
||||
|
||||
@pytest.mark.parametrize("arg", [
|
||||
['a_u', 403],
|
||||
|
||||
@@ -7,6 +7,7 @@ from django.urls import reverse
|
||||
from django_scopes import scopes_disabled
|
||||
|
||||
from cookbook.models import UserSpace
|
||||
from recipes import settings
|
||||
|
||||
LIST_URL = 'api:space-list'
|
||||
DETAIL_URL = 'api:space-detail'
|
||||
@@ -45,7 +46,6 @@ def test_list_multiple(u1_s1, space_1, space_2):
|
||||
assert u1_response['id'] == space_1.id
|
||||
|
||||
|
||||
|
||||
@pytest.mark.parametrize("arg", [
|
||||
['a_u', 403],
|
||||
['g1_s1', 403],
|
||||
@@ -70,9 +70,9 @@ def test_update(arg, request, space_1, a1_s1):
|
||||
|
||||
@pytest.mark.parametrize("arg", [
|
||||
['a_u', 403],
|
||||
['g1_s1', 403],
|
||||
['u1_s1', 403],
|
||||
['a1_s1', 405],
|
||||
['g1_s1', 201],
|
||||
['u1_s1', 201],
|
||||
['a1_s1', 201],
|
||||
])
|
||||
def test_add(arg, request, u1_s2):
|
||||
c = request.getfixturevalue(arg[0])
|
||||
@@ -90,3 +90,59 @@ def test_delete(u1_s1, u1_s2, a1_s1, space_1):
|
||||
# event the space owner cannot delete his space over the api (this might change later but for now it's only available in the UI)
|
||||
r = a1_s1.delete(reverse(DETAIL_URL, args={space_1.id}))
|
||||
assert r.status_code == 405
|
||||
|
||||
|
||||
def test_superuser_parameters(space_1, a1_s1, s1_s1):
|
||||
# ------- test as normal user -------
|
||||
response = a1_s1.post(reverse(LIST_URL), {'name': 'test', 'ai_enabled': not settings.SPACE_AI_ENABLED, 'ai_credits_monthly': settings.SPACE_AI_CREDITS_MONTHLY + 100, 'ai_credits_balance': 100},
|
||||
content_type='application/json')
|
||||
|
||||
assert response.status_code == 201
|
||||
response = json.loads(response.content)
|
||||
assert response['ai_enabled'] == settings.SPACE_AI_ENABLED
|
||||
assert response['ai_credits_monthly'] == settings.SPACE_AI_CREDITS_MONTHLY
|
||||
assert response['ai_credits_balance'] == 0
|
||||
|
||||
space_1.created_by = auth.get_user(a1_s1)
|
||||
space_1.ai_enabled = False
|
||||
space_1.ai_credits_monthly = 0
|
||||
space_1.ai_credits_balance = 0
|
||||
space_1.save()
|
||||
|
||||
response = a1_s1.patch(reverse(DETAIL_URL, args={space_1.id}), {'ai_enabled': True, 'ai_credits_monthly': 100, 'ai_credits_balance': 100},
|
||||
content_type='application/json')
|
||||
|
||||
assert response.status_code == 200
|
||||
|
||||
space_1.refresh_from_db()
|
||||
assert space_1.ai_enabled == False
|
||||
assert space_1.ai_credits_monthly == 0
|
||||
assert space_1.ai_credits_balance == 0
|
||||
|
||||
# ------- test as superuser -------
|
||||
|
||||
response = s1_s1.post(reverse(LIST_URL),
|
||||
{'name': 'test', 'ai_enabled': not settings.SPACE_AI_ENABLED, 'ai_credits_monthly': settings.SPACE_AI_CREDITS_MONTHLY + 100, 'ai_credits_balance': 100},
|
||||
content_type='application/json')
|
||||
|
||||
assert response.status_code == 201
|
||||
response = json.loads(response.content)
|
||||
assert response['ai_enabled'] == settings.SPACE_AI_ENABLED
|
||||
assert response['ai_credits_monthly'] == settings.SPACE_AI_CREDITS_MONTHLY
|
||||
assert response['ai_credits_balance'] == 0
|
||||
|
||||
space_1.created_by = auth.get_user(s1_s1)
|
||||
space_1.ai_enabled = False
|
||||
space_1.ai_credits_monthly = 0
|
||||
space_1.ai_credits_balance = 0
|
||||
space_1.save()
|
||||
|
||||
response = s1_s1.patch(reverse(DETAIL_URL, args={space_1.id}), {'ai_enabled': True, 'ai_credits_monthly': 100, 'ai_credits_balance': 100},
|
||||
content_type='application/json')
|
||||
|
||||
assert response.status_code == 200
|
||||
|
||||
space_1.refresh_from_db()
|
||||
assert space_1.ai_enabled == True
|
||||
assert space_1.ai_credits_monthly == 100
|
||||
assert space_1.ai_credits_balance == 100
|
||||
|
||||
@@ -5,6 +5,8 @@ from django.contrib import auth
|
||||
from django.urls import reverse
|
||||
from django_scopes import scopes_disabled
|
||||
|
||||
from cookbook.models import UserSpace
|
||||
|
||||
LIST_URL = 'api:userspace-list'
|
||||
DETAIL_URL = 'api:userspace-detail'
|
||||
|
||||
@@ -13,10 +15,10 @@ DETAIL_URL = 'api:userspace-detail'
|
||||
['a_u', 403, 0],
|
||||
['g1_s1', 200, 1], # sees only own user space
|
||||
['u1_s1', 200, 1],
|
||||
['a1_s1', 200, 3], # sees user space of all users in space
|
||||
['a2_s1', 200, 1],
|
||||
['a1_s1', 200, 4], # admins can see all other members
|
||||
['a2_s1', 200, 4],
|
||||
])
|
||||
def test_list_permission(arg, request, space_1, g1_s1, u1_s1, a1_s1):
|
||||
def test_list_permission(arg, request, space_1, g1_s1, u1_s1, a1_s1, a2_s1):
|
||||
space_1.created_by = auth.get_user(a1_s1)
|
||||
space_1.save()
|
||||
|
||||
@@ -27,6 +29,18 @@ def test_list_permission(arg, request, space_1, g1_s1, u1_s1, a1_s1):
|
||||
assert len(json.loads(result.content)['results']) == arg[2]
|
||||
|
||||
|
||||
def test_list_all_personal(space_2, u1_s1):
|
||||
result = u1_s1.get(reverse('api:userspace-all-personal'))
|
||||
assert result.status_code == 200
|
||||
assert len(json.loads(result.content)) == 1
|
||||
|
||||
UserSpace.objects.create(user=auth.get_user(u1_s1), space=space_2)
|
||||
|
||||
result = u1_s1.get(reverse('api:userspace-all-personal'))
|
||||
assert result.status_code == 200
|
||||
assert len(json.loads(result.content)) == 2
|
||||
|
||||
|
||||
@pytest.mark.parametrize("arg", [
|
||||
['a_u', 403],
|
||||
['g1_s1', 403],
|
||||
|
||||
@@ -78,10 +78,11 @@ urlpatterns = [
|
||||
|
||||
path('setup/', views.setup, name='view_setup'),
|
||||
path('no-group/', views.no_groups, name='view_no_group'),
|
||||
path('space-overview/', views.space_overview, name='view_space_overview'),
|
||||
path('switch-space/<int:space_id>', views.switch_space, name='view_switch_space'),
|
||||
path('no-perm/', views.no_perm, name='view_no_perm'),
|
||||
#path('space-overview/', views.space_overview, name='view_space_overview'),
|
||||
#path('switch-space/<int:space_id>', views.switch_space, name='view_switch_space'),
|
||||
#path('no-perm/', views.no_perm, name='view_no_perm'),
|
||||
path('invite/<slug:token>', views.invite_link, name='view_invite'),
|
||||
path('invite/<slug:token>/', views.invite_link, name='view_invite'),
|
||||
|
||||
path('system/', views.system, name='view_system'),
|
||||
path('plugin/update/', views.plugin_update, name='view_plugin_update'),
|
||||
|
||||
@@ -18,8 +18,6 @@ import litellm
|
||||
import redis
|
||||
import requests
|
||||
from PIL import UnidentifiedImageError
|
||||
from PIL.ImImagePlugin import number
|
||||
from PIL.features import check
|
||||
from django.contrib import messages
|
||||
from django.contrib.auth.models import Group, User
|
||||
from django.contrib.postgres.search import TrigramSimilarity
|
||||
@@ -35,7 +33,6 @@ from django.shortcuts import get_object_or_404, redirect
|
||||
from django.urls import reverse
|
||||
from django.utils import timezone
|
||||
from django.utils.dateparse import parse_datetime
|
||||
from django.utils.datetime_safe import date
|
||||
from django.utils.translation import gettext as _
|
||||
from django_scopes import scopes_disabled
|
||||
from drf_spectacular.types import OpenApiTypes
|
||||
@@ -76,7 +73,7 @@ from cookbook.helper.permission_helper import (CustomIsAdmin, CustomIsOwner, Cus
|
||||
CustomTokenHasScope, CustomUserPermission, IsReadOnlyDRF,
|
||||
above_space_limit,
|
||||
group_required, has_group_permission, is_space_owner,
|
||||
switch_user_active_space, CustomAiProviderPermission
|
||||
switch_user_active_space, CustomAiProviderPermission, IsCreateDRF
|
||||
)
|
||||
from cookbook.helper.recipe_search import RecipeSearch
|
||||
from cookbook.helper.recipe_url_import import clean_dict, get_from_youtube_scraper, get_images_from_soup
|
||||
@@ -134,7 +131,7 @@ class LoggingMixin(object):
|
||||
|
||||
if settings.REDIS_HOST:
|
||||
try:
|
||||
d = date.today().isoformat()
|
||||
d = timezone.now().isoformat()
|
||||
space = request.space
|
||||
endpoint = request.resolver_match.url_name
|
||||
|
||||
@@ -182,7 +179,10 @@ class StandardFilterModelViewSet(viewsets.ModelViewSet):
|
||||
queryset = self.queryset
|
||||
query = self.request.query_params.get('query', None)
|
||||
if query is not None:
|
||||
queryset = queryset.filter(name__icontains=query)
|
||||
try:
|
||||
queryset = queryset.filter(name__icontains=query)
|
||||
except FieldError:
|
||||
pass
|
||||
|
||||
updated_at = self.request.query_params.get('updated_at', None)
|
||||
if updated_at is not None:
|
||||
@@ -544,9 +544,9 @@ class GroupViewSet(LoggingMixin, viewsets.ModelViewSet):
|
||||
class SpaceViewSet(LoggingMixin, viewsets.ModelViewSet):
|
||||
queryset = Space.objects
|
||||
serializer_class = SpaceSerializer
|
||||
permission_classes = [IsReadOnlyDRF & CustomIsGuest | CustomIsOwner & CustomIsAdmin & CustomTokenHasReadWriteScope]
|
||||
permission_classes = [((IsReadOnlyDRF | IsCreateDRF) & CustomIsGuest) | CustomIsOwner & CustomIsAdmin & CustomTokenHasReadWriteScope]
|
||||
pagination_class = DefaultPagination
|
||||
http_method_names = ['get', 'patch']
|
||||
http_method_names = ['get', 'post', 'put', 'patch']
|
||||
|
||||
def get_queryset(self):
|
||||
return self.queryset.filter(
|
||||
@@ -565,7 +565,7 @@ class SpaceViewSet(LoggingMixin, viewsets.ModelViewSet):
|
||||
class UserSpaceViewSet(LoggingMixin, viewsets.ModelViewSet):
|
||||
queryset = UserSpace.objects
|
||||
serializer_class = UserSpaceSerializer
|
||||
permission_classes = [(CustomIsSpaceOwner | CustomIsOwnerReadOnly) & CustomTokenHasReadWriteScope]
|
||||
permission_classes = [(CustomIsSpaceOwner | (IsReadOnlyDRF & CustomIsUser) | CustomIsOwnerReadOnly) & CustomTokenHasReadWriteScope]
|
||||
http_method_names = ['get', 'put', 'patch', 'delete']
|
||||
pagination_class = DefaultPagination
|
||||
|
||||
@@ -579,10 +579,23 @@ class UserSpaceViewSet(LoggingMixin, viewsets.ModelViewSet):
|
||||
if internal_note is not None:
|
||||
self.queryset = self.queryset.filter(internal_note=internal_note)
|
||||
|
||||
if is_space_owner(self.request.user, self.request.space):
|
||||
# >= admins can see all users, guest/user can only see themselves
|
||||
if has_group_permission(self.request.user, ['admin']):
|
||||
return self.queryset.filter(space=self.request.space)
|
||||
else:
|
||||
return self.queryset.filter(user=self.request.user, space=self.request.space)
|
||||
return self.queryset.filter(space=self.request.space, user=self.request.user)
|
||||
|
||||
@extend_schema(responses=UserSpaceSerializer(many=True))
|
||||
@decorators.action(detail=False, pagination_class=DefaultPagination, methods=['GET'], serializer_class=UserSpaceSerializer, )
|
||||
def all_personal(self, request):
|
||||
"""
|
||||
return all userspaces for the user requesting the endpoint
|
||||
:param request:
|
||||
:return:
|
||||
"""
|
||||
with scopes_disabled():
|
||||
self.queryset = self.queryset.filter(user=self.request.user)
|
||||
return Response(self.serializer_class(self.queryset.all(), many=True, context={'request': self.request}).data)
|
||||
|
||||
|
||||
class UserPreferenceViewSet(LoggingMixin, viewsets.ModelViewSet):
|
||||
@@ -1222,7 +1235,19 @@ class IngredientViewSet(LoggingMixin, viewsets.ModelViewSet):
|
||||
return self.serializer_class
|
||||
|
||||
def get_queryset(self):
|
||||
queryset = self.queryset.filter(step__recipe__space=self.request.space)
|
||||
queryset = self.queryset.prefetch_related('food',
|
||||
'food__properties',
|
||||
'food__properties__property_type',
|
||||
'food__inherit_fields',
|
||||
'food__supermarket_category',
|
||||
'food__onhand_users',
|
||||
'food__substitute',
|
||||
'food__child_inherit_fields',
|
||||
'unit',
|
||||
'unit__unit_conversion_base_relation',
|
||||
'unit__unit_conversion_base_relation__base_unit',
|
||||
'unit__unit_conversion_converted_relation',
|
||||
'unit__unit_conversion_converted_relation__converted_unit', ).filter(step__recipe__space=self.request.space)
|
||||
food = self.request.query_params.get('food', None)
|
||||
if food and re.match(r'^(\d)+$', food):
|
||||
queryset = queryset.filter(food_id=food)
|
||||
@@ -1893,8 +1918,8 @@ class InviteLinkViewSet(LoggingMixin, StandardFilterModelViewSet):
|
||||
if internal_note is not None:
|
||||
self.queryset = self.queryset.filter(internal_note=internal_note)
|
||||
|
||||
unused = self.request.query_params.get('unused', False)
|
||||
if unused:
|
||||
used = self.request.query_params.get('used', False)
|
||||
if not used:
|
||||
self.queryset = self.queryset.filter(used_by=None)
|
||||
|
||||
if is_space_owner(self.request.user, self.request.space):
|
||||
@@ -2267,7 +2292,13 @@ class AppImportView(APIView):
|
||||
files = []
|
||||
for f in request.FILES.getlist('files'):
|
||||
files.append({'file': io.BytesIO(f.read()), 'name': f.name})
|
||||
t = threading.Thread(target=integration.do_import, args=[files, il, form.cleaned_data['duplicates']])
|
||||
t = threading.Thread(target=integration.do_import,
|
||||
args=[files, il, form.cleaned_data['duplicates']],
|
||||
kwargs={'meal_plans': form.cleaned_data['meal_plans'],
|
||||
'shopping_lists': form.cleaned_data['shopping_lists'],
|
||||
'nutrition_per_serving': form.cleaned_data['nutrition_per_serving']
|
||||
}
|
||||
)
|
||||
t.setDaemon(True)
|
||||
t.start()
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@ from cookbook.integration.copymethat import CopyMeThat
|
||||
from cookbook.integration.default import Default
|
||||
from cookbook.integration.domestica import Domestica
|
||||
from cookbook.integration.mealie import Mealie
|
||||
from cookbook.integration.mealie1 import Mealie1
|
||||
from cookbook.integration.mealmaster import MealMaster
|
||||
from cookbook.integration.melarecipes import MelaRecipes
|
||||
from cookbook.integration.nextcloud_cookbook import NextcloudCookbook
|
||||
@@ -45,6 +46,8 @@ def get_integration(request, export_type):
|
||||
return NextcloudCookbook(request, export_type)
|
||||
if export_type == ImportExportBase.MEALIE:
|
||||
return Mealie(request, export_type)
|
||||
if export_type == ImportExportBase.MEALIE1:
|
||||
return Mealie1(request, export_type)
|
||||
if export_type == ImportExportBase.CHOWDOWN:
|
||||
return Chowdown(request, export_type)
|
||||
if export_type == ImportExportBase.SAFFRON:
|
||||
|
||||
@@ -54,7 +54,7 @@ def hook(request, token):
|
||||
f = ingredient_parser.get_food(food)
|
||||
u = ingredient_parser.get_unit(unit)
|
||||
|
||||
ShoppingListEntry.objects.create(food=f, unit=u, amount=amount, created_by=request.user, space=request.space)
|
||||
ShoppingListEntry.objects.create(food=f, unit=u, amount=max(1, amount), created_by=request.user, space=request.space)
|
||||
|
||||
return JsonResponse({'data': data['message']['text']})
|
||||
except Exception:
|
||||
|
||||
@@ -21,7 +21,7 @@ from django.http import HttpResponseRedirect, JsonResponse, HttpResponse
|
||||
from django.shortcuts import get_object_or_404, render
|
||||
from django.templatetags.static import static
|
||||
from django.urls import reverse, reverse_lazy
|
||||
from django.utils.datetime_safe import date
|
||||
from django.utils import timezone
|
||||
from django.utils.translation import gettext as _
|
||||
from django_scopes import scopes_disabled
|
||||
from drf_spectacular.views import SpectacularRedocView, SpectacularSwaggerView
|
||||
@@ -42,6 +42,9 @@ def index(request, path=None, resource=None):
|
||||
if User.objects.count() < 1 and 'django.contrib.auth.backends.RemoteUserBackend' not in settings.AUTHENTICATION_BACKENDS:
|
||||
return HttpResponseRedirect(reverse_lazy('view_setup'))
|
||||
|
||||
if 'signup_token' in request.session:
|
||||
return HttpResponseRedirect(reverse('view_invite', args=[request.session.pop('signup_token', '')]))
|
||||
|
||||
if request.user.is_authenticated or re.search(r'/recipe/\d+/', request.path[:512]) and request.GET.get('share'):
|
||||
return render(request, 'frontend/tandoor.html', {})
|
||||
else:
|
||||
@@ -98,7 +101,7 @@ def space_overview(request):
|
||||
max_users=settings.SPACE_DEFAULT_MAX_USERS,
|
||||
allow_sharing=settings.SPACE_DEFAULT_ALLOW_SHARING,
|
||||
ai_enabled=settings.SPACE_AI_ENABLED,
|
||||
ai_credits_monthly=settings.SPACE_AI_CREDITS_MONTHLY,)
|
||||
ai_credits_monthly=settings.SPACE_AI_CREDITS_MONTHLY, )
|
||||
|
||||
user_space = UserSpace.objects.create(space=created_space, user=request.user, active=False)
|
||||
user_space.groups.add(Group.objects.filter(name='admin').get())
|
||||
@@ -223,7 +226,7 @@ def system(request):
|
||||
total_stats = ['All', int(r.get('api:request-count'))]
|
||||
|
||||
for i in range(0, 6):
|
||||
d = (date.today() - timedelta(days=i)).isoformat()
|
||||
d = (timezone.now() - timedelta(days=i)).isoformat()
|
||||
api_stats[0].append(d)
|
||||
api_space_stats[0].append(d)
|
||||
total_stats.append(int(r.get(f'api:request-count:{d}')) if r.get(f'api:request-count:{d}') else 0)
|
||||
@@ -234,7 +237,7 @@ def system(request):
|
||||
endpoint = x[0].decode('utf-8')
|
||||
endpoint_stats = [endpoint, x[1]]
|
||||
for i in range(0, 6):
|
||||
d = (date.today() - timedelta(days=i)).isoformat()
|
||||
d = (timezone.now() - timedelta(days=i)).isoformat()
|
||||
endpoint_stats.append(r.zscore(f'api:endpoint-request-count:{d}', endpoint))
|
||||
api_stats.append(endpoint_stats)
|
||||
|
||||
@@ -243,7 +246,7 @@ def system(request):
|
||||
if space := Space.objects.filter(pk=s).first():
|
||||
space_stats = [space.name, x[1]]
|
||||
for i in range(0, 6):
|
||||
d = (date.today() - timedelta(days=i)).isoformat()
|
||||
d = (timezone.now() - timedelta(days=i)).isoformat()
|
||||
space_stats.append(r.zscore(f'api:space-request-count:{d}', s))
|
||||
api_space_stats.append(space_stats)
|
||||
|
||||
@@ -322,7 +325,7 @@ def invite_link(request, token):
|
||||
try:
|
||||
token = UUID(token, version=4)
|
||||
except ValueError:
|
||||
messages.add_message(request, messages.ERROR, _('Malformed Invite Link supplied!'))
|
||||
print('Malformed Invite Link supplied!')
|
||||
return HttpResponseRedirect(reverse('index'))
|
||||
|
||||
if link := InviteLink.objects.filter(valid_until__gte=datetime.today(), used_by=None, uuid=token).first():
|
||||
@@ -331,22 +334,17 @@ def invite_link(request, token):
|
||||
link.used_by = request.user
|
||||
link.save()
|
||||
|
||||
user_space = UserSpace.objects.create(user=request.user, space=link.space, internal_note=link.internal_note, invite_link=link, active=False)
|
||||
|
||||
if request.user.userspace_set.count() == 1:
|
||||
user_space.active = True
|
||||
user_space.save()
|
||||
UserSpace.objects.filter(user=request.user).update(active=False)
|
||||
user_space = UserSpace.objects.create(user=request.user, space=link.space, internal_note=link.internal_note, invite_link=link, active=True)
|
||||
|
||||
user_space.groups.add(link.group)
|
||||
|
||||
messages.add_message(request, messages.SUCCESS, _('Successfully joined space.'))
|
||||
return HttpResponseRedirect(reverse('view_space_overview'))
|
||||
return HttpResponseRedirect(reverse('index'))
|
||||
else:
|
||||
request.session['signup_token'] = str(token)
|
||||
return HttpResponseRedirect(reverse('account_signup'))
|
||||
|
||||
messages.add_message(request, messages.ERROR, _('Invite Link not valid or already used!'))
|
||||
return HttpResponseRedirect(reverse('view_space_overview'))
|
||||
return HttpResponseRedirect(reverse('index'))
|
||||
|
||||
|
||||
def report_share_abuse(request, token):
|
||||
|
||||
@@ -97,10 +97,17 @@ Follow these steps to import your recipes
|
||||
|
||||
Mealie provides structured data similar to nextcloud.
|
||||
|
||||
!!! WARNING "Versions"
|
||||
There are two different versions of the Mealie importer. One for all backups created prior to Version 1.0 and one for all after.
|
||||
|
||||
!!! INFO "Versions"
|
||||
The Mealie UI does not indicate weather or not nutrition information is stored per serving or per recipe. This choice is left to the user. During the import you will have to choose
|
||||
how Tandoor should treat your nutrition data.
|
||||
|
||||
To migrate your recipes
|
||||
|
||||
1. Go to your Mealie settings and create a new Backup.
|
||||
2. Download the backup by clicking on it and pressing download (this wasn't working for me, so I had to manually pull it from the server).
|
||||
1. Go to your Mealie admin settings and create a new backup.
|
||||
2. Download the backup.
|
||||
3. Upload the entire `.zip` file to the importer page and import everything.
|
||||
|
||||
## Chowdown
|
||||
|
||||
@@ -565,8 +565,6 @@ else:
|
||||
|
||||
USE_I18N = True
|
||||
|
||||
USE_L10N = True
|
||||
|
||||
USE_TZ = True
|
||||
|
||||
LANGUAGES = [
|
||||
@@ -594,8 +592,18 @@ LANGUAGES = [
|
||||
|
||||
AWS_ENABLED = True if os.getenv('S3_ACCESS_KEY', False) else False
|
||||
|
||||
STORAGES = {
|
||||
"default": {
|
||||
"BACKEND": "django.core.files.storage.FileSystemStorage",
|
||||
},
|
||||
# Serve static files with gzip
|
||||
"staticfiles": {
|
||||
"BACKEND": "whitenoise.storage.CompressedManifestStaticFilesStorage",
|
||||
},
|
||||
}
|
||||
|
||||
if os.getenv('S3_ACCESS_KEY', ''):
|
||||
DEFAULT_FILE_STORAGE = 'cookbook.helper.CustomStorageClass.CachedS3Boto3Storage'
|
||||
STORAGES['default']['BACKEND'] = 'cookbook.helper.CustomStorageClass.CachedS3Boto3Storage'
|
||||
|
||||
AWS_ACCESS_KEY_ID = os.getenv('S3_ACCESS_KEY', '')
|
||||
AWS_SECRET_ACCESS_KEY = os.getenv('S3_SECRET_ACCESS_KEY', '')
|
||||
@@ -610,14 +618,9 @@ if os.getenv('S3_ACCESS_KEY', ''):
|
||||
if os.getenv('S3_CUSTOM_DOMAIN', ''):
|
||||
AWS_S3_CUSTOM_DOMAIN = os.getenv('S3_CUSTOM_DOMAIN', '')
|
||||
|
||||
MEDIA_URL = os.getenv('MEDIA_URL', '/media/')
|
||||
MEDIA_ROOT = os.getenv('MEDIA_ROOT', os.path.join(BASE_DIR, "mediafiles"))
|
||||
else:
|
||||
MEDIA_URL = os.getenv('MEDIA_URL', '/media/')
|
||||
MEDIA_ROOT = os.getenv('MEDIA_ROOT', os.path.join(BASE_DIR, "mediafiles"))
|
||||
|
||||
# Serve static files with gzip
|
||||
STATICFILES_STORAGE = 'whitenoise.storage.CompressedManifestStaticFilesStorage'
|
||||
MEDIA_URL = os.getenv('MEDIA_URL', '/media/')
|
||||
MEDIA_ROOT = os.getenv('MEDIA_ROOT', os.path.join(BASE_DIR, "mediafiles"))
|
||||
|
||||
# settings for cross site origin (CORS)
|
||||
# all origins allowed to support bookmarklet
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
Django==4.2.24
|
||||
Django==5.2.6
|
||||
cryptography===45.0.5
|
||||
django-annoying==0.10.6
|
||||
django-cleanup==9.0.0
|
||||
django-crispy-forms==2.4
|
||||
crispy-bootstrap4==2025.6
|
||||
djangorestframework==3.15.2
|
||||
djangorestframework==3.16.1
|
||||
drf-spectacular==0.27.1
|
||||
drf-spectacular-sidecar==2025.7.1
|
||||
drf-spectacular-sidecar==2025.8.1
|
||||
drf-writable-nested==0.7.2
|
||||
django-oauth-toolkit==2.4.0
|
||||
django-debug-toolbar==4.3.0
|
||||
@@ -16,7 +16,7 @@ lxml==5.3.1
|
||||
Markdown==3.7
|
||||
Pillow==11.3.0
|
||||
psycopg2-binary==2.9.10
|
||||
python-dotenv==1.0.0
|
||||
python-dotenv==1.1.1
|
||||
requests==2.32.4
|
||||
six==1.17.0
|
||||
webdavclient3==3.14.6
|
||||
@@ -33,9 +33,9 @@ recipe-scrapers==15.8.0
|
||||
django-scopes==2.0.0
|
||||
django-treebeard==4.7.1
|
||||
django-cors-headers==4.6.0
|
||||
django-storages==1.14.2
|
||||
django-storages==1.14.6
|
||||
boto3==1.28.75
|
||||
django-prometheus==2.3.1
|
||||
django-prometheus==2.4.1
|
||||
django-hCaptcha==0.2.0
|
||||
python-ldap==3.4.4
|
||||
django-auth-ldap==4.6.0
|
||||
|
||||
@@ -19,11 +19,11 @@
|
||||
"pinia": "^3.0.2",
|
||||
"vue": "^3.5.13",
|
||||
"vue-draggable-plus": "^0.6.0",
|
||||
"vue-i18n": "^11.1.10",
|
||||
"vue-i18n": "^11.1.11",
|
||||
"vue-router": "^4.5.0",
|
||||
"vue-simple-calendar": "7.1.0",
|
||||
"vuedraggable": "^4.1.0",
|
||||
"vuetify": "^3.9.3"
|
||||
"vuetify": "^3.9.7"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@fortawesome/fontawesome-free": "^6.7.2",
|
||||
@@ -35,10 +35,10 @@
|
||||
"esbuild-register": "^3.6.0",
|
||||
"jsdom": "^26.1.0",
|
||||
"typescript": "^5.8.3",
|
||||
"vite": "6.3.5",
|
||||
"vite-plugin-pwa": "^1.0.2",
|
||||
"vite": "7.1.5",
|
||||
"vite-plugin-pwa": "^1.0.3",
|
||||
"vite-plugin-vuetify": "^2.1.1",
|
||||
"vue-tsc": "^2.2.8",
|
||||
"vue-tsc": "^3.0.6",
|
||||
"workbox-background-sync": "^7.3.0",
|
||||
"workbox-build": "^7.3.0",
|
||||
"workbox-core": "^7.3.0",
|
||||
|
||||
@@ -156,13 +156,16 @@ const router = useRouter()
|
||||
const isPrintMode = useMediaQuery('print')
|
||||
|
||||
onMounted(() => {
|
||||
useUserPreferenceStore()
|
||||
useUserPreferenceStore().init()
|
||||
})
|
||||
|
||||
/**
|
||||
* global title update handler, might be overridden by page specific handlers
|
||||
*/
|
||||
router.afterEach((to, from) => {
|
||||
if(to.name == 'StartPage' && !useUserPreferenceStore().activeSpace.spaceSetupCompleted != undefined &&!useUserPreferenceStore().activeSpace.spaceSetupCompleted && useUserPreferenceStore().activeSpace.createdBy.id! == useUserPreferenceStore().userSettings.user.id!){
|
||||
router.push({name: 'WelcomePage'})
|
||||
}
|
||||
nextTick(() => {
|
||||
if (to.meta.title) {
|
||||
title.value = t(to.meta.title)
|
||||
|
||||
@@ -18,6 +18,7 @@ let routes = [
|
||||
{path: '/', component: () => import("@/pages/StartPage.vue"), name: 'StartPage' },
|
||||
{path: '/search', redirect: {name: 'StartPage'}},
|
||||
{path: '/test', component: () => import("@/pages/TestPage.vue"), name: 'view_test'},
|
||||
{path: '/welcome', component: () => import("@/pages/WelcomePage.vue"), name: 'WelcomePage', meta: {title: 'Welcome'}},
|
||||
{path: '/help', component: () => import("@/pages/HelpPage.vue"), name: 'HelpPage', meta: {title: 'Help'}},
|
||||
{
|
||||
path: '/settings', component: () => import("@/pages/SettingsPage.vue"), name: 'SettingsPage', redirect: '/settings/account',
|
||||
@@ -28,8 +29,6 @@ let routes = [
|
||||
{path: 'meal-plan', component: () => import("@/components/settings/MealPlanSettings.vue"), name: 'MealPlanSettings', meta: {title: 'Settings'}},
|
||||
{path: 'search', component: () => import("@/components/settings/SearchSettings.vue"), name: 'SearchSettings', meta: {title: 'Settings'}},
|
||||
{path: 'space', component: () => import("@/components/settings/SpaceSettings.vue"), name: 'SpaceSettings', meta: {title: 'Settings'}},
|
||||
{path: 'space-members', component: () => import("@/components/settings/SpaceMemberSettings.vue"), name: 'SpaceMemberSettings', meta: {title: 'Settings'}},
|
||||
{path: 'user-space', component: () => import("@/components/settings/UserSpaceSettings.vue"), name: 'UserSpaceSettings', meta: {title: 'Settings'}},
|
||||
{path: 'open-data-import', component: () => import("@/components/settings/OpenDataImportSettings.vue"), name: 'OpenDataImportSettings', meta: {title: 'Settings'}},
|
||||
{path: 'export', component: () => import("@/components/settings/ExportDataSettings.vue"), name: 'ExportDataSettings', meta: {title: 'Settings'}},
|
||||
{path: 'api', component: () => import("@/components/settings/ApiSettings.vue"), name: 'ApiSettings', meta: {title: 'Settings'}},
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
|
||||
<v-row v-if=" props.importLog.importedRecipes != undefined && props.importLog.totalRecipes != undefined">
|
||||
<v-row v-if="props.importLog.importedRecipes != undefined && props.importLog.totalRecipes != undefined">
|
||||
<v-col>
|
||||
<v-progress-linear :model-value="(props.importLog.importedRecipes/props.importLog.totalRecipes)*100" height="24" color="primary">
|
||||
{{ props.importLog.importedRecipes }} / {{ props.importLog.totalRecipes }}
|
||||
@@ -8,9 +8,9 @@
|
||||
</v-col>
|
||||
</v-row>
|
||||
|
||||
<v-row>
|
||||
<v-row v-if="props.importLog.importedRecipes != undefined && props.importLog.totalRecipes != undefined">
|
||||
<v-col>
|
||||
<v-textarea :model-value="importLog.msg" max-rows="25" auto-grow></v-textarea>
|
||||
<v-textarea :model-value="importLog.msg" max-rows="25" :loading="importLog.running" auto-grow></v-textarea>
|
||||
</v-col>
|
||||
</v-row>
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
<recipe-image :height="itemHeight" :width="itemHeight" :recipe="mealPlan.recipe"></recipe-image>
|
||||
</div>
|
||||
<div class="flex-column flex-grow-0 pa-1">
|
||||
<span class="font-light" :class="{'two-line-text': detailedItems,'one-line-text': !detailedItems,}">
|
||||
<span class="font-light" :class="{'three-line-text': detailedItems,'one-line-text': !detailedItems,}">
|
||||
<i class="fas fa-shopping-cart fa-xs float-left" v-if="mealPlan.shopping"/>
|
||||
{{ itemTitle }}
|
||||
</span>
|
||||
@@ -82,4 +82,13 @@ const itemTitle = computed(() => {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.three-line-text {
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 3;
|
||||
-webkit-box-orient: vertical;
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -98,9 +98,9 @@ const planItems = computed(() => {
|
||||
*/
|
||||
const calendarItemHeight = computed(() => {
|
||||
if (lgAndUp.value && useUserPreferenceStore().deviceSettings.mealplan_displayPeriod == 'week') {
|
||||
return '2.6rem'
|
||||
return '3.5rem'
|
||||
} else {
|
||||
return '1.3rem'
|
||||
return '1.6rem'
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
@@ -120,6 +120,7 @@ const hasFoodProperties = computed(() => {
|
||||
let propertiesFound = false
|
||||
for (const [key, fp] of Object.entries(recipe.value.foodProperties)) {
|
||||
if (fp.total_value !== 0) {
|
||||
console.log(fp, fp.total_value)
|
||||
propertiesFound = true
|
||||
}
|
||||
}
|
||||
@@ -189,7 +190,7 @@ const dialogProperty = ref<undefined | PropertyWrapper>(undefined)
|
||||
const loading = ref(false)
|
||||
|
||||
onMounted(() => {
|
||||
if (!hasFoodProperties) {
|
||||
if (!hasFoodProperties.value) {
|
||||
sourceSelectedToShow.value = "recipe"
|
||||
}
|
||||
})
|
||||
|
||||
@@ -33,9 +33,8 @@
|
||||
</template>
|
||||
<v-list-item-title class="font-weight-bold">
|
||||
{{ c.createdBy.displayName }}
|
||||
|
||||
</v-list-item-title>
|
||||
<v-list-item-subtitle>{{ c.comment }}</v-list-item-subtitle>
|
||||
<span>{{ c.comment }}</span>
|
||||
|
||||
<v-list-item-subtitle class="font-italic mt-1" v-if="c.servings != null && c.servings > 0">
|
||||
|
||||
@@ -49,7 +48,7 @@
|
||||
<template #append>
|
||||
<v-list-item-action class="flex-column align-end">
|
||||
<v-rating density="comfortable" size="x-small" color="tandoor" v-model="c.rating" half-increments readonly
|
||||
v-if="c.rating != undefined"></v-rating>
|
||||
v-if="c.rating != undefined" style="overflow: hidden"></v-rating>
|
||||
<v-spacer></v-spacer>
|
||||
<v-tooltip location="top" :text="DateTime.fromJSDate(c.createdAt).toLocaleString(DateTime.DATETIME_MED)" v-if="c.createdAt != undefined">
|
||||
<template v-slot:activator="{ props }">
|
||||
@@ -121,6 +120,7 @@ function recLoadCookLog(recipeId: number, page: number = 1) {
|
||||
* reset new cook log from with proper defaults
|
||||
*/
|
||||
function resetForm() {
|
||||
newCookLog.value = {} as CookLog
|
||||
newCookLog.value.servings = props.recipe.servings
|
||||
newCookLog.value.createdAt = new Date()
|
||||
newCookLog.value.recipe = props.recipe.id!
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<v-list-item class="swipe-container border-t-sm" :id="itemContainerId" @touchend="handleSwipe()"
|
||||
<v-list-item class="swipe-container border-t-sm mt-0 mb-0 pt-0 pb-0 pe-0 pa-0" :id="itemContainerId" @touchend="handleSwipe()" @click="dialog = true;"
|
||||
v-if="isShoppingListFoodVisible(props.shoppingListFood, useUserPreferenceStore().deviceSettings)"
|
||||
>
|
||||
<!-- <div class="swipe-action" :class="{'bg-success': !isChecked , 'bg-warning': isChecked }">-->
|
||||
@@ -7,15 +7,15 @@
|
||||
<!-- </div>-->
|
||||
|
||||
|
||||
<div class="flex-grow-1 p-2" @click="dialog = true;">
|
||||
<div class="flex-grow-1 p-2">
|
||||
<div class="d-flex">
|
||||
<div class="d-flex flex-column pr-2">
|
||||
<div class="d-flex flex-column pr-2 pl-4">
|
||||
<span v-for="a in amounts" v-bind:key="a.key">
|
||||
<span>
|
||||
<i class="fas fa-check text-success fa-fw" v-if="a.checked"></i>
|
||||
<i class="fas fa-clock-rotate-left text-info fa-fw" v-if="a.delayed"></i> <b>
|
||||
<span :class="{'text-disabled': a.checked || a.delayed}" class="text-no-wrap">
|
||||
<span v-if="amounts.length > 1 || (amounts.length == 1 && a.amount != 1)">{{ $n(a.amount) }}</span>
|
||||
<span v-if="amounts.length > 1 || (amounts.length == 1 && a.amount != 1) || a.unit">{{ $n(a.amount) }}</span>
|
||||
<span class="ms-1" v-if="a.unit">{{ pluralString(a.unit, a.amount) }}</span>
|
||||
</span>
|
||||
</b>
|
||||
@@ -30,10 +30,13 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<template v-slot:[checkBtnSlot]>
|
||||
<v-btn color="success" @click.native.stop="useShoppingStore().setEntriesCheckedState(entries, !isChecked, true);"
|
||||
:class="{'btn-success': !isChecked, 'btn-warning': isChecked}" :icon="actionButtonIcon" variant="plain">
|
||||
</v-btn>
|
||||
<div class="ps-3 pe-3" @click.native.stop="useShoppingStore().setEntriesCheckedState(entries, !isChecked, true);">
|
||||
<v-btn color="success" size="large"
|
||||
:class="{'btn-success': !isChecked, 'btn-warning': isChecked}" :icon="actionButtonIcon" variant="plain">
|
||||
</v-btn>
|
||||
</div>
|
||||
<!-- <i class="d-print-none fa-fw fas" :class="{'fa-check': !isChecked , 'fa-cart-plus': isChecked }"></i>-->
|
||||
</template>
|
||||
|
||||
|
||||
72
vue3/src/components/display/SpaceLimitsInfo.vue
Normal file
72
vue3/src/components/display/SpaceLimitsInfo.vue
Normal file
@@ -0,0 +1,72 @@
|
||||
<template>
|
||||
<v-row v-if="props.space.name != undefined">
|
||||
<v-col cols="12" md="4">
|
||||
<v-card :to="{name: 'SearchPage'}">
|
||||
<v-card-title><i class="fa-solid fa-book"></i> {{ $t('Recipes') }}</v-card-title>
|
||||
<v-card-text>{{ $n(props.space.recipeCount) }} / {{ props.space.maxRecipes == 0 ? '∞' : $n(props.space.maxRecipes) }}</v-card-text>
|
||||
<v-progress-linear :color="isSpaceAboveRecipeLimit(props.space) ? 'error' : 'success'" height="10"
|
||||
:model-value="(props.space.recipeCount / props.space.maxRecipes) * 100"></v-progress-linear>
|
||||
</v-card>
|
||||
</v-col>
|
||||
<v-col cols="12" md="4">
|
||||
<v-card :to="{name: 'ModelListPage', params: {model: 'UserSpace'}}">
|
||||
|
||||
<v-card-title><i class="fa-solid fa-users"></i> {{ $t('Users') }}</v-card-title>
|
||||
<v-card-text>{{ $n(props.space.userCount) }} / {{ props.space.maxUsers == 0 ? '∞' : $n(props.space.maxUsers) }}</v-card-text>
|
||||
<v-progress-linear :color="isSpaceAboveUserLimit(props.space) ? 'error' : 'success'" height="10"
|
||||
:model-value="(props.space.userCount / props.space.maxUsers) * 100"></v-progress-linear>
|
||||
</v-card>
|
||||
</v-col>
|
||||
<v-col cols="12" md="4">
|
||||
<v-card :to="{name: 'ModelListPage', params: {model: 'UserFile'}}">
|
||||
<v-card-title><i class="fa-solid fa-file"></i> {{ $t('Files') }}</v-card-title>
|
||||
<v-card-text v-if="props.space.maxFileStorageMb > -1">{{ $n(Math.round(props.space.fileSizeMb)) }} /
|
||||
{{ props.space.maxFileStorageMb == 0 ? '∞' : $n(props.space.maxFileStorageMb) }}
|
||||
MB
|
||||
</v-card-text>
|
||||
<v-card-text v-if="props.space.maxFileStorageMb == -1">{{ $t('file_upload_disabled') }}</v-card-text>
|
||||
<v-progress-linear v-if="props.space.maxFileStorageMb > -1" :color="isSpaceAboveStorageLimit(props.space) ? 'error' : 'success'" height="10"
|
||||
:model-value="(props.space.fileSizeMb / props.space.maxFileStorageMb) * 100"></v-progress-linear>
|
||||
</v-card>
|
||||
</v-col>
|
||||
|
||||
<v-col cols="12" md="6">
|
||||
<v-card :to="{name: 'ModelListPage', params: {model: 'AiLog'}}">
|
||||
<v-card-title><i class="fa-solid hand-holding-dollar"></i> {{ $t('MonthlyCredits') }}</v-card-title>
|
||||
<v-card-text>{{ $n(props.space.aiMonthlyCreditsUsed) }} / {{ $n(props.space.aiCreditsMonthly) }} {{ $t('Credits') }}
|
||||
</v-card-text>
|
||||
<v-progress-linear :model-value="props.space.aiMonthlyCreditsUsed" :max="props.space.aiCreditsMonthly" height="10"
|
||||
></v-progress-linear>
|
||||
</v-card>
|
||||
</v-col>
|
||||
|
||||
<v-col cols="12" md="6">
|
||||
<v-card :to="{name: 'ModelListPage', params: {model: 'AiLog'}}">
|
||||
<v-card-title><i class="fa-solid hand-holding-dollar"></i> {{ $t('AiCreditsBalance') }}</v-card-title>
|
||||
<v-card-text>{{ $n(props.space.aiCreditsBalance) }} {{ $t('Credits') }}
|
||||
</v-card-text>
|
||||
<v-progress-linear height="10"
|
||||
></v-progress-linear>
|
||||
</v-card>
|
||||
</v-col>
|
||||
</v-row>
|
||||
|
||||
</template>
|
||||
|
||||
|
||||
<script setup lang="ts">
|
||||
|
||||
import {PropType} from "vue";
|
||||
import {Space} from "@/openapi";
|
||||
import {isSpaceAboveRecipeLimit, isSpaceAboveStorageLimit, isSpaceAboveUserLimit} from "@/utils/logic_utils.ts";
|
||||
import {useUserPreferenceStore} from "@/stores/UserPreferenceStore.ts";
|
||||
|
||||
const props = defineProps({
|
||||
space: {type: {} as PropType<Space>, required: true},
|
||||
})
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
@@ -71,7 +71,7 @@ const mergedIngredients = computed(() => {
|
||||
// Add ingredients from steps
|
||||
props.steps.forEach(step => {
|
||||
step.ingredients.forEach(ingredient => {
|
||||
if (ingredient.food && !ingredient.isHeader && !ingredient.noAmount) {
|
||||
if (ingredient.food && !ingredient.isHeader ) {
|
||||
ingredients.push(ingredient);
|
||||
}
|
||||
});
|
||||
@@ -80,7 +80,7 @@ const mergedIngredients = computed(() => {
|
||||
if (step.stepRecipeData) {
|
||||
step.stepRecipeData.steps?.forEach((subStep: Step) => {
|
||||
subStep.ingredients.forEach((ingredient: Ingredient) => {
|
||||
if (ingredient.food && !ingredient.isHeader && !ingredient.noAmount) {
|
||||
if (ingredient.food && !ingredient.isHeader) {
|
||||
ingredients.push(ingredient);
|
||||
}
|
||||
});
|
||||
|
||||
47
vue3/src/components/display/ThankYouNote.vue
Normal file
47
vue3/src/components/display/ThankYouNote.vue
Normal file
@@ -0,0 +1,47 @@
|
||||
<template>
|
||||
<v-alert color="primary" variant="tonal" v-if="useUserPreferenceStore().serverSettings.hosted">
|
||||
<v-alert-title>
|
||||
<v-row>
|
||||
<v-col>
|
||||
<v-avatar image="../../assets/logo_color.svg" class="me-2"></v-avatar>
|
||||
{{ $t('ThankYou') }}!
|
||||
|
||||
</v-col>
|
||||
<v-col>
|
||||
<v-btn color="primary" class="float-right" href="https://tandoor.dev/manage" target="_blank">{{ $t('ManageSubscription') }}</v-btn>
|
||||
|
||||
</v-col>
|
||||
</v-row>
|
||||
</v-alert-title>
|
||||
<p class="mt-2">{{ $t('ThanksTextHosted') }}</p>
|
||||
</v-alert>
|
||||
|
||||
<v-alert color="primary" variant="tonal" v-if="!useUserPreferenceStore().serverSettings.hosted">
|
||||
<v-alert-title>
|
||||
<v-row>
|
||||
<v-col>
|
||||
<v-avatar image="../../assets/logo_color.svg" class="me-2"></v-avatar>
|
||||
{{ $t('ThankYou') }}!
|
||||
|
||||
</v-col>
|
||||
<v-col>
|
||||
<v-btn color="primary" class="float-right" href="https://github.com/sponsors/vabene1111" target="_blank"><i class="fa-brands fa-github"></i> GitHub Sponsors
|
||||
</v-btn>
|
||||
|
||||
</v-col>
|
||||
</v-row>
|
||||
</v-alert-title>
|
||||
<p class="mt-2">{{ $t('ThanksTextSelfhosted') }}</p>
|
||||
</v-alert>
|
||||
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
|
||||
import {useUserPreferenceStore} from "@/stores/UserPreferenceStore.ts";
|
||||
</script>
|
||||
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
51
vue3/src/components/inputs/LanguageSelect.vue
Normal file
51
vue3/src/components/inputs/LanguageSelect.vue
Normal file
@@ -0,0 +1,51 @@
|
||||
<template>
|
||||
<v-select
|
||||
:label="$t('Language')"
|
||||
v-model="$i18n.locale"
|
||||
:items="availableLocalizations"
|
||||
item-title="language"
|
||||
item-value="code"
|
||||
@update:model-value="updateLanguage()"
|
||||
></v-select>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
|
||||
import {onMounted, ref} from "vue";
|
||||
import {ApiApi, Localization} from "@/openapi";
|
||||
import {ErrorMessageType, useMessageStore} from "@/stores/MessageStore.ts";
|
||||
import {useI18n} from "vue-i18n";
|
||||
|
||||
const availableLocalizations = ref([] as Localization[])
|
||||
const {locale} = useI18n()
|
||||
|
||||
|
||||
onMounted(() => {
|
||||
const api = new ApiApi()
|
||||
|
||||
api.apiLocalizationList().then(r => {
|
||||
availableLocalizations.value = r
|
||||
}).catch(err => {
|
||||
useMessageStore().addError(ErrorMessageType.FETCH_ERROR, err)
|
||||
})
|
||||
})
|
||||
|
||||
/**
|
||||
* update the django language cookie
|
||||
* this is used by django to inject the language into the template which in turn
|
||||
* sets the frontend language in i18n.ts when the frontend is initialized
|
||||
*/
|
||||
function updateLanguage() {
|
||||
const expires = new Date();
|
||||
expires.setTime(expires.getTime() + (100 * 365 * 24 * 60 * 60 * 1000));
|
||||
document.cookie = `django_language=${locale.value}; expires=${expires.toUTCString()}; path=/`;
|
||||
location.reload()
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
@@ -98,7 +98,7 @@
|
||||
<script setup lang="ts">
|
||||
|
||||
import {ApiApi, UserFile, UserFileFromJSON} from "@/openapi";
|
||||
import {onMounted, ref} from "vue";
|
||||
import {onMounted, ref, watch} from "vue";
|
||||
import {DateTime} from "luxon";
|
||||
import {ErrorMessageType, PreparedMessage, useMessageStore} from "@/stores/MessageStore";
|
||||
import {getCookie} from "@/utils/cookie";
|
||||
@@ -131,8 +131,13 @@ const tableHeaders = ref([
|
||||
])
|
||||
|
||||
onMounted(() => {
|
||||
//TODO move to open function of file tab
|
||||
loadFiles()
|
||||
|
||||
})
|
||||
|
||||
watch(() => dialog.value, (value, oldValue) => {
|
||||
if (value && !oldValue) {
|
||||
loadFiles()
|
||||
}
|
||||
})
|
||||
|
||||
function loadFiles() {
|
||||
|
||||
142
vue3/src/components/model_editors/SpaceEditor.vue
Normal file
142
vue3/src/components/model_editors/SpaceEditor.vue
Normal file
@@ -0,0 +1,142 @@
|
||||
<template>
|
||||
<model-editor-base
|
||||
:loading="loading"
|
||||
:dialog="dialog"
|
||||
@save="saveObject"
|
||||
@delete="deleteObject"
|
||||
@close="emit('close'); editingObjChanged = false"
|
||||
:is-update="isUpdate()"
|
||||
:is-changed="editingObjChanged"
|
||||
:model-class="modelClass"
|
||||
:object-name="editingObjName()">
|
||||
|
||||
<v-card-text class="pa-0">
|
||||
<v-tabs v-model="tab" :disabled="loading" grow>
|
||||
<v-tab value="space">{{ $t('Space') }}</v-tab>
|
||||
<v-tab value="cosmetic">{{ $t('Cosmetic') }}</v-tab>
|
||||
<v-tab value="ai">{{ $t('AI') }}</v-tab>
|
||||
</v-tabs>
|
||||
</v-card-text>
|
||||
|
||||
<v-card-text>
|
||||
<v-tabs-window v-model="tab">
|
||||
<v-tabs-window-item value="space">
|
||||
<v-form :disabled="loading">
|
||||
|
||||
<v-text-field :label="$t('Name')" v-model="editingObj.name"></v-text-field>
|
||||
|
||||
<user-file-field v-model="editingObj.image" :label="$t('Image')" :hint="$t('CustomImageHelp')" persistent-hint></user-file-field>
|
||||
|
||||
<v-textarea v-model="editingObj.message" :label="$t('Message')" clearable></v-textarea>
|
||||
|
||||
<space-limits-info :space="editingObj" :show-thank-you="false" v-if="isUpdate()"></space-limits-info>
|
||||
|
||||
</v-form>
|
||||
</v-tabs-window-item>
|
||||
<v-tabs-window-item value="cosmetic">
|
||||
<v-label class="mt-4">{{ $t('Nav_Color') }}</v-label>
|
||||
<v-color-picker v-model="editingObj.navBgColor" class="mb-4" mode="hex" :modes="['hex']" show-swatches
|
||||
:swatches="[['#ddbf86'],['#b98766'],['#b55e4f'],['#82aa8b'],['#385f84']]"></v-color-picker>
|
||||
<v-btn class="mb-4" @click="editingObj.navBgColor = ''">{{ $t('Reset') }}</v-btn>
|
||||
|
||||
<user-file-field v-model="editingObj.navLogo" :label="$t('Logo')" :hint="$t('CustomNavLogoHelp')" persistent-hint></user-file-field>
|
||||
|
||||
<user-file-field v-model="editingObj.logoColor32" :label="$t('Logo') + ' 32x32px'"></user-file-field>
|
||||
<user-file-field v-model="editingObj.logoColor128" :label="$t('Logo') + ' 128x128px'"></user-file-field>
|
||||
<user-file-field v-model="editingObj.logoColor144" :label="$t('Logo') + ' 144x144px'"></user-file-field>
|
||||
<user-file-field v-model="editingObj.logoColor180" :label="$t('Logo') + ' 180x180px'"></user-file-field>
|
||||
<user-file-field v-model="editingObj.logoColor192" :label="$t('Logo') + ' 192x192px'"></user-file-field>
|
||||
<user-file-field v-model="editingObj.logoColor512" :label="$t('Logo') + ' 512x512px'"></user-file-field>
|
||||
<user-file-field v-model="editingObj.logoColorSvg" :label="$t('Logo') + ' SVG'"></user-file-field>
|
||||
<user-file-field v-model="editingObj.customSpaceTheme" :label="$t('CustomTheme') + ' CSS'"></user-file-field>
|
||||
|
||||
</v-tabs-window-item>
|
||||
<v-tabs-window-item value="ai">
|
||||
<p class="text-disabled font-italic text-body-2">
|
||||
<span v-if="useUserPreferenceStore().serverSettings.hosted">
|
||||
{{ $t('AISettingsHostedHelp') }}
|
||||
</span>
|
||||
<span v-else>
|
||||
{{ $t('SettingsOnlySuperuser') }}
|
||||
</span>
|
||||
</p>
|
||||
|
||||
<v-checkbox v-model="editingObj.aiEnabled" :label="$t('Enabled')" :disabled="!useUserPreferenceStore().userSettings.user.isSuperuser" hide-details></v-checkbox>
|
||||
|
||||
<template v-if="editingObj.aiEnabled">
|
||||
<model-select model="AiProvider" :label="$t('Default')" v-model="editingObj.aiDefaultProvider"></model-select>
|
||||
|
||||
<v-number-input v-model="editingObj.aiCreditsMonthly" :precision="2" :label="$t('MonthlyCredits')"
|
||||
:disabled="!useUserPreferenceStore().userSettings.user.isSuperuser"></v-number-input>
|
||||
<v-number-input v-model="editingObj.aiCreditsBalance" :precision="4" :label="$t('AiCreditsBalance')"
|
||||
:disabled="!useUserPreferenceStore().userSettings.user.isSuperuser"></v-number-input>
|
||||
|
||||
</template>
|
||||
</v-tabs-window-item>
|
||||
|
||||
</v-tabs-window>
|
||||
</v-card-text>
|
||||
</model-editor-base>
|
||||
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
|
||||
import {onMounted, PropType, ref, watch} from "vue";
|
||||
import {ApiApi, ConnectorConfig, Space} from "@/openapi";
|
||||
import ModelEditorBase from "@/components/model_editors/ModelEditorBase.vue";
|
||||
import {useModelEditorFunctions} from "@/composables/useModelEditorFunctions";
|
||||
import UserFileField from "@/components/inputs/UserFileField.vue";
|
||||
import ModelSelect from "@/components/inputs/ModelSelect.vue";
|
||||
import {useUserPreferenceStore} from "@/stores/UserPreferenceStore.ts";
|
||||
import editor from "mavon-editor";
|
||||
import SpaceLimitsInfo from "@/components/display/SpaceLimitsInfo.vue";
|
||||
|
||||
const props = defineProps({
|
||||
item: {type: {} as PropType<Space>, required: false, default: null},
|
||||
itemId: {type: [Number, String], required: false, default: undefined},
|
||||
itemDefaults: {type: {} as PropType<Space>, required: false, default: {} as Space},
|
||||
dialog: {type: Boolean, default: false}
|
||||
})
|
||||
|
||||
const emit = defineEmits(['create', 'save', 'delete', 'close', 'changedState'])
|
||||
const {
|
||||
setupState,
|
||||
deleteObject,
|
||||
saveObject,
|
||||
isUpdate,
|
||||
editingObjName,
|
||||
loading,
|
||||
editingObj,
|
||||
editingObjChanged,
|
||||
modelClass
|
||||
} = useModelEditorFunctions<Space>('Space', emit)
|
||||
|
||||
/**
|
||||
* watch prop changes and re-initialize editor
|
||||
* required to embed editor directly into pages and be able to change item from the outside
|
||||
*/
|
||||
watch([() => props.item, () => props.itemId], () => {
|
||||
initializeEditor()
|
||||
})
|
||||
|
||||
// object specific data (for selects/display)
|
||||
|
||||
const tab = ref("space")
|
||||
|
||||
onMounted(() => {
|
||||
initializeEditor()
|
||||
})
|
||||
|
||||
/**
|
||||
* component specific state setup logic
|
||||
*/
|
||||
function initializeEditor() {
|
||||
setupState(props.item, props.itemId, {itemDefaults: props.itemDefaults})
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
@@ -2,7 +2,10 @@
|
||||
<v-form>
|
||||
<p class="text-h6">{{ $t('Profile') }}</p>
|
||||
<v-divider class="mb-3"></v-divider>
|
||||
<v-text-field :label="$t('Username')" v-model="user.username" disabled :hint="$t('theUsernameCannotBeChanged')" persistent-hint></v-text-field>
|
||||
|
||||
<thank-you-note></thank-you-note>
|
||||
|
||||
<v-text-field class="mt-3" :label="$t('Username')" v-model="user.username" disabled :hint="$t('theUsernameCannotBeChanged')" persistent-hint></v-text-field>
|
||||
|
||||
<!-- <v-label>Avatar</v-label><br/>-->
|
||||
<!-- <v-avatar class="mt-3 mb-3" style="height: 10vh; width: 10vh" color="info">V</v-avatar> Feature coming in a future Version of Tandoor.-->
|
||||
@@ -39,6 +42,7 @@ import {ApiApi, User} from "@/openapi";
|
||||
import {ErrorMessageType, PreparedMessage, useMessageStore} from "@/stores/MessageStore";
|
||||
import {useUserPreferenceStore} from "@/stores/UserPreferenceStore";
|
||||
import {useDjangoUrls} from "@/composables/useDjangoUrls";
|
||||
import ThankYouNote from "@/components/display/ThankYouNote.vue";
|
||||
|
||||
const {getDjangoUrl} = useDjangoUrls()
|
||||
|
||||
|
||||
@@ -3,14 +3,7 @@
|
||||
<p class="text-h6">{{ $t('Cosmetic') }}</p>
|
||||
<v-divider class="mb-3"></v-divider>
|
||||
|
||||
<v-select
|
||||
:label="$t('Language')"
|
||||
v-model="$i18n.locale"
|
||||
:items="availableLocalizations"
|
||||
item-title="language"
|
||||
item-value="code"
|
||||
@update:model-value="updateLanguage()"
|
||||
></v-select>
|
||||
<language-select></language-select>
|
||||
|
||||
<v-label>{{$t('Nav_Color')}}</v-label>
|
||||
<v-color-picker v-model="useUserPreferenceStore().userSettings.navBgColor" mode="hex" :modes="['hex']" show-swatches :swatches="[['#ddbf86'],['#b98766'],['#b55e4f'],['#82aa8b'],['#385f84']]"></v-color-picker>
|
||||
@@ -54,10 +47,10 @@ import {ApiApi, Localization} from "@/openapi";
|
||||
import {ErrorMessageType, useMessageStore} from "@/stores/MessageStore";
|
||||
import {useI18n} from "vue-i18n";
|
||||
import {useUserPreferenceStore} from "@/stores/UserPreferenceStore";
|
||||
import LanguageSelect from "@/components/inputs/LanguageSelect.vue";
|
||||
|
||||
const {locale, t} = useI18n()
|
||||
const {t} = useI18n()
|
||||
|
||||
const availableLocalizations = ref([] as Localization[])
|
||||
const availableDefaultPages = ref([
|
||||
{page: 'SEARCH', label: t('Search')},
|
||||
{page: 'SHOPPING', label: t('Shopping_list')},
|
||||
@@ -65,29 +58,10 @@ const availableDefaultPages = ref([
|
||||
{page: 'BOOKS', label: t('Books')},
|
||||
])
|
||||
|
||||
|
||||
onMounted(() => {
|
||||
const api = new ApiApi()
|
||||
|
||||
api.apiLocalizationList().then(r => {
|
||||
availableLocalizations.value = r
|
||||
}).catch(err => {
|
||||
useMessageStore().addError(ErrorMessageType.FETCH_ERROR, err)
|
||||
})
|
||||
})
|
||||
|
||||
/**
|
||||
* update the django language cookie
|
||||
* this is used by django to inject the language into the template which in turn
|
||||
* sets the frontend language in i18n.ts when the frontend is initialized
|
||||
*/
|
||||
function updateLanguage() {
|
||||
const expires = new Date();
|
||||
expires.setTime(expires.getTime() + (100 * 365 * 24 * 60 * 60 * 1000));
|
||||
document.cookie = `django_language=${locale.value}; expires=${expires.toUTCString()}; path=/`;
|
||||
location.reload()
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
<template>
|
||||
<p class="text-h6">{{ $t('Open_Data_Import') }}</p>
|
||||
<p class="text-h4">{{ $t('Open_Data_Import') }}</p>
|
||||
<v-divider></v-divider>
|
||||
<p class="text-subtitle-2">{{ $t('Data_Import_Info') }}</p>
|
||||
<v-btn href="https://github.com/TandoorRecipes/open-tandoor-data" target="_blank" rel="noreferrer nofollow">{{ $t('Learn_More') }}</v-btn>
|
||||
<p class="text-subtitle-1">{{ $t('Data_Import_Info') }} <a href="https://github.com/TandoorRecipes/open-tandoor-data" target="_blank" rel="noreferrer nofollow">{{ $t('Learn_More') }}</a></p>
|
||||
|
||||
<v-select :items="metadata.versions" :label="$t('Language')" class="mt-2" v-model="requestData.selectedVersion" :loading="loading"></v-select>
|
||||
<v-select :items="metadata.versions" :label="$t('Language')" class="mt-4" v-model="requestData.selectedVersion" :loading="loading"></v-select>
|
||||
|
||||
<v-row v-if="requestData.selectedVersion">
|
||||
<v-col>
|
||||
@@ -29,10 +28,10 @@
|
||||
<td>{{ metadata[requestData.selectedVersion][d] }}</td>
|
||||
<td>
|
||||
<template v-if="responseData[d]">
|
||||
<i class="fas fa-plus-circle"></i> {{ responseData[d].totalCreated }} {{ $t('Created') }} <br/>
|
||||
<i class="fas fa-pencil-alt"></i> {{ responseData[d].totalUpdated }} {{ $t('Updated') }} <br/>
|
||||
<i class="fas fa-forward"></i> {{ responseData[d].totalUntouched}} {{ $t('Unchanged') }} <br/>
|
||||
<i class="fas fa-exclamation-circle"></i> {{ responseData[d].totalErrored }} {{ $t('Error') }}
|
||||
<p v-if="responseData[d].totalCreated > 0" ><i class="fas fa-plus-circle"></i> {{ responseData[d].totalCreated }} {{ $t('Created') }}</p>
|
||||
<p v-if="responseData[d].totalUpdated > 0"><i class="fas fa-pencil-alt"></i> {{ responseData[d].totalUpdated }} {{ $t('Updated') }}</p>
|
||||
<p v-if="responseData[d].totalUntouched > 0"><i class="fas fa-forward"></i> {{ responseData[d].totalUntouched }} {{ $t('Unchanged') }}</p>
|
||||
<p v-if="responseData[d].totalErrored > 0"><i class="fas fa-exclamation-circle"></i> {{ responseData[d].totalErrored }} {{ $t('Error') }}</p>
|
||||
</template>
|
||||
</td>
|
||||
</tr>
|
||||
@@ -102,7 +101,6 @@ function importOpenData() {
|
||||
})
|
||||
|
||||
api.apiImportOpenDataCreate({importOpenData: requestData.value}).then(r => {
|
||||
console.log(r)
|
||||
responseData.value = r
|
||||
}).catch(err => {
|
||||
useMessageStore().addError(ErrorMessageType.FETCH_ERROR, err)
|
||||
|
||||
@@ -1,122 +0,0 @@
|
||||
<template>
|
||||
<v-form>
|
||||
<p class="text-h6">{{ $t('SpaceMembers') }}</p>
|
||||
<v-divider></v-divider>
|
||||
<p class="text-subtitle-2">{{ $t('SpaceMemberHelp') }}</p>
|
||||
|
||||
<v-data-table :items="spaceUserSpaces" :headers="userTableHeaders" density="compact" :hide-default-footer="spaceUserSpaces.length < 10" class="mt-3">
|
||||
<template #item.groups="{item}">
|
||||
<span v-for="g in item.groups">{{ g.name }} </span>
|
||||
</template>
|
||||
|
||||
<template #item.edit="{item}">
|
||||
<v-btn color="edit" size="small" v-if="item.user.id != useUserPreferenceStore().activeSpace.createdBy.id">
|
||||
<v-icon icon="$edit"></v-icon>
|
||||
<model-edit-dialog model="UserSpace" :item="item" @delete="deleteUserSpace(item)" class="mt-2"></model-edit-dialog>
|
||||
</v-btn>
|
||||
<v-chip color="edit" v-else>{{ $t('Owner') }}</v-chip>
|
||||
</template>
|
||||
</v-data-table>
|
||||
|
||||
<p class="text-h6 mt-3">{{ $t('Invites') }}
|
||||
<v-btn size="small" class="float-right" prepend-icon="$create" color="create">
|
||||
{{ $t('New') }}
|
||||
<model-edit-dialog model="InviteLink" @delete="deleteInviteLink" @create="item => spaceInviteLinks.push(item)" class="mt-2"></model-edit-dialog>
|
||||
</v-btn>
|
||||
</p>
|
||||
<v-divider class="mb-3"></v-divider>
|
||||
|
||||
<v-data-table :items="spaceInviteLinks" :headers="inviteTableHeaders" density="compact" :hide-default-footer="spaceInviteLinks.length < 10">
|
||||
<template #item.reusable="{item}">
|
||||
<v-icon icon="fa-solid fa-check" color="success" v-if="item.reusable"></v-icon>
|
||||
<v-icon icon="fa-solid fa-times" color="error" v-if="!item.reusable"></v-icon>
|
||||
</template>
|
||||
|
||||
<template #item.edit="{item}">
|
||||
<btn-copy size="small" :copy-value="inviteLinkUrl(item)" class="me-1"></btn-copy>
|
||||
<v-btn color="edit" size="small">
|
||||
<v-icon icon="$edit"></v-icon>
|
||||
<model-edit-dialog model="InviteLink" :item="item" @delete="deleteInviteLink(item)" class="mt-2"></model-edit-dialog>
|
||||
</v-btn>
|
||||
</template>
|
||||
</v-data-table>
|
||||
</v-form>
|
||||
</template>
|
||||
|
||||
|
||||
<script setup lang="ts">
|
||||
|
||||
|
||||
import {onMounted, ref} from "vue";
|
||||
import {ApiApi, InviteLink, UserSpace} from "@/openapi";
|
||||
import {ErrorMessageType, useMessageStore} from "@/stores/MessageStore";
|
||||
import {useI18n} from "vue-i18n";
|
||||
import BtnCopy from "@/components/buttons/BtnCopy.vue";
|
||||
import {useUserPreferenceStore} from "@/stores/UserPreferenceStore";
|
||||
import ModelEditDialog from "@/components/dialogs/ModelEditDialog.vue";
|
||||
import {useDjangoUrls} from "@/composables/useDjangoUrls.ts";
|
||||
|
||||
const {t} = useI18n()
|
||||
|
||||
const spaceUserSpaces = ref([] as UserSpace[])
|
||||
const spaceInviteLinks = ref([] as InviteLink[])
|
||||
|
||||
const userTableHeaders = [
|
||||
{title: t('Username'), key: 'user.username'},
|
||||
{title: t('Role'), key: 'groups'},
|
||||
{title: t('Edit'), key: 'edit', align: 'end'},
|
||||
]
|
||||
|
||||
const inviteTableHeaders = [
|
||||
{title: 'ID', key: 'id'},
|
||||
{title: t('Email'), key: 'email'},
|
||||
{title: t('Role'), key: 'group.name'},
|
||||
{title: t('Reusable'), key: 'reusable'},
|
||||
{title: t('Edit'), key: 'edit', align: 'end'},
|
||||
]
|
||||
|
||||
onMounted(() => {
|
||||
const api = new ApiApi()
|
||||
|
||||
api.apiUserSpaceList().then(r => {
|
||||
spaceUserSpaces.value = r.results
|
||||
}).catch(err => {
|
||||
useMessageStore().addError(ErrorMessageType.FETCH_ERROR, err)
|
||||
})
|
||||
|
||||
api.apiInviteLinkList({unused: true}).then(r => {
|
||||
spaceInviteLinks.value = r.results
|
||||
}).catch(err => {
|
||||
useMessageStore().addError(ErrorMessageType.FETCH_ERROR, err)
|
||||
})
|
||||
})
|
||||
|
||||
/**
|
||||
* delete userspace from client list (database handled by editor)
|
||||
* @param userSpace UserSpace object that was deleted
|
||||
*/
|
||||
function deleteUserSpace(userSpace: UserSpace) {
|
||||
spaceUserSpaces.value.splice(spaceUserSpaces.value.indexOf(userSpace) - 1, 1)
|
||||
}
|
||||
|
||||
/**
|
||||
* delete invite link from client list (database handled by editor)
|
||||
* @param inviteLink InviteLink object that was deleted
|
||||
*/
|
||||
function deleteInviteLink(inviteLink: InviteLink) {
|
||||
spaceInviteLinks.value.splice(spaceInviteLinks.value.indexOf(inviteLink) - 1, 1)
|
||||
}
|
||||
|
||||
/**
|
||||
* returns url for invite link
|
||||
* @param inviteLink InviteLink object to create url for
|
||||
*/
|
||||
function inviteLinkUrl(inviteLink: InviteLink) {
|
||||
return useDjangoUrls().getDjangoUrl(`/invite/${inviteLink.uuid}`)
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
@@ -3,163 +3,17 @@
|
||||
<p class="text-h6">{{ useUserPreferenceStore().activeSpace.name }}</p>
|
||||
<v-divider class="mb-3"></v-divider>
|
||||
|
||||
<v-row v-if="space.name != undefined">
|
||||
<v-col cols="12" md="4">
|
||||
<v-card>
|
||||
<v-card-title><i class="fa-solid fa-book"></i> {{ $t('Recipes') }}</v-card-title>
|
||||
<v-card-text>{{ $n(space.recipeCount) }} / {{ space.maxRecipes == 0 ? '∞' : $n(space.maxRecipes) }}</v-card-text>
|
||||
<v-progress-linear :color="isSpaceAboveRecipeLimit(space) ? 'error' : 'success'" height="10"
|
||||
:model-value="(space.recipeCount / space.maxRecipes) * 100"></v-progress-linear>
|
||||
</v-card>
|
||||
</v-col>
|
||||
<v-col cols="12" md="4">
|
||||
<v-card>
|
||||
|
||||
<v-card-title><i class="fa-solid fa-users"></i> {{ $t('Users') }}</v-card-title>
|
||||
<v-card-text>{{ $n(space.userCount) }} / {{ space.maxUsers == 0 ? '∞' : $n(space.maxUsers) }}</v-card-text>
|
||||
<v-progress-linear :color="isSpaceAboveUserLimit(space) ? 'error' : 'success'" height="10"
|
||||
:model-value="(space.userCount / space.maxUsers) * 100"></v-progress-linear>
|
||||
</v-card>
|
||||
</v-col>
|
||||
<v-col cols="12" md="4">
|
||||
<v-card>
|
||||
<v-card-title><i class="fa-solid fa-file"></i> {{ $t('Files') }}</v-card-title>
|
||||
<v-card-text v-if="space.maxFileStorageMb > -1">{{ $n(Math.round(space.fileSizeMb)) }} / {{ space.maxFileStorageMb == 0 ? '∞' : $n(space.maxFileStorageMb) }}
|
||||
MB
|
||||
</v-card-text>
|
||||
<v-card-text v-if="space.maxFileStorageMb == -1">{{ $t('file_upload_disabled') }}</v-card-text>
|
||||
<v-progress-linear v-if="space.maxFileStorageMb > -1" :color="isSpaceAboveStorageLimit(space) ? 'error' : 'success'" height="10"
|
||||
:model-value="(space.fileSizeMb / space.maxFileStorageMb) * 100"></v-progress-linear>
|
||||
</v-card>
|
||||
</v-col>
|
||||
</v-row>
|
||||
<v-divider class="mt-3 mb-3"></v-divider>
|
||||
|
||||
<v-alert color="primary" variant="tonal" v-if="useUserPreferenceStore().serverSettings.hosted">
|
||||
<v-alert-title>
|
||||
<v-row>
|
||||
<v-col>
|
||||
<v-avatar image="../../assets/logo_color.svg" class="me-2"></v-avatar>
|
||||
{{ $t('ThankYou') }}!
|
||||
|
||||
</v-col>
|
||||
<v-col>
|
||||
<v-btn color="primary" class="float-right" href="https://tandoor.dev/manage" target="_blank">{{ $t('ManageSubscription') }}</v-btn>
|
||||
|
||||
</v-col>
|
||||
</v-row>
|
||||
</v-alert-title>
|
||||
<p class="mt-2">{{ $t('ThanksTextHosted') }}</p>
|
||||
</v-alert>
|
||||
|
||||
<v-alert color="primary" variant="tonal" v-if="!useUserPreferenceStore().serverSettings.hosted">
|
||||
<v-alert-title>
|
||||
<v-row>
|
||||
<v-col>
|
||||
<v-avatar image="../../assets/logo_color.svg" class="me-2"></v-avatar>
|
||||
{{ $t('ThankYou') }}!
|
||||
|
||||
</v-col>
|
||||
<v-col>
|
||||
<v-btn color="primary" class="float-right" href="https://github.com/sponsors/vabene1111" target="_blank"><i class="fa-brands fa-github"></i> GitHub Sponsors
|
||||
</v-btn>
|
||||
|
||||
</v-col>
|
||||
</v-row>
|
||||
</v-alert-title>
|
||||
<p class="mt-2">{{ $t('ThanksTextSelfhosted') }}</p>
|
||||
</v-alert>
|
||||
|
||||
|
||||
<p class="text-h6 mt-2">{{ $t('Settings') }}</p>
|
||||
<v-divider class="mb-2"></v-divider>
|
||||
|
||||
<user-file-field v-model="space.image" :label="$t('Image')" :hint="$t('CustomImageHelp')" persistent-hint></user-file-field>
|
||||
|
||||
|
||||
<v-textarea v-model="space.message" :label="$t('Message')"></v-textarea>
|
||||
<v-btn color="success" @click="updateSpace()" prepend-icon="$save">{{ $t('Save') }}</v-btn>
|
||||
|
||||
<p class="text-h6 mt-2">{{ $t('AI') }}</p>
|
||||
<v-divider class="mb-2"></v-divider>
|
||||
<p class="text-disabled font-italic text-body-2">
|
||||
<span v-if="useUserPreferenceStore().serverSettings.hosted">
|
||||
{{ $t('AISettingsHostedHelp') }}
|
||||
</span>
|
||||
<span v-else>
|
||||
{{ $t('SettingsOnlySuperuser') }}
|
||||
</span>
|
||||
</p>
|
||||
|
||||
<v-checkbox v-model="space.aiEnabled" :label="$t('Enabled')" :disabled="!useUserPreferenceStore().userSettings.user.isSuperuser" hide-details></v-checkbox>
|
||||
|
||||
<template v-if="space.aiEnabled">
|
||||
<model-select model="AiProvider" :label="$t('Default')" v-model="space.aiDefaultProvider"></model-select>
|
||||
|
||||
<v-number-input v-model="space.aiCreditsMonthly" :precision="2" :label="$t('MonthlyCredits')" :disabled="!useUserPreferenceStore().userSettings.user.isSuperuser"></v-number-input>
|
||||
<v-number-input v-model="space.aiCreditsBalance" :precision="4" :label="$t('AiCreditsBalance')" :disabled="!useUserPreferenceStore().userSettings.user.isSuperuser"></v-number-input>
|
||||
|
||||
</template>
|
||||
<v-btn color="success" @click="updateSpace()" prepend-icon="$save">{{ $t('Save') }}</v-btn>
|
||||
|
||||
<v-divider class="mt-4 mb-2"></v-divider>
|
||||
<h2>{{ $t('Cosmetic') }}</h2>
|
||||
<span>{{ $t('Space_Cosmetic_Settings') }}</span>
|
||||
|
||||
<v-label class="mt-4">{{ $t('Nav_Color') }}</v-label>
|
||||
<v-color-picker v-model="space.navBgColor" class="mb-4" mode="hex" :modes="['hex']" show-swatches
|
||||
:swatches="[['#ddbf86'],['#b98766'],['#b55e4f'],['#82aa8b'],['#385f84']]"></v-color-picker>
|
||||
<v-btn class="mb-4" @click="space.navBgColor = ''">{{ $t('Reset') }}</v-btn>
|
||||
|
||||
<user-file-field v-model="space.navLogo" :label="$t('Logo')" :hint="$t('CustomNavLogoHelp')" persistent-hint></user-file-field>
|
||||
|
||||
<user-file-field v-model="space.logoColor32" :label="$t('Logo') + ' 32x32px'"></user-file-field>
|
||||
<user-file-field v-model="space.logoColor128" :label="$t('Logo') + ' 128x128px'"></user-file-field>
|
||||
<user-file-field v-model="space.logoColor144" :label="$t('Logo') + ' 144x144px'"></user-file-field>
|
||||
<user-file-field v-model="space.logoColor180" :label="$t('Logo') + ' 180x180px'"></user-file-field>
|
||||
<user-file-field v-model="space.logoColor192" :label="$t('Logo') + ' 192x192px'"></user-file-field>
|
||||
<user-file-field v-model="space.logoColor512" :label="$t('Logo') + ' 512x512px'"></user-file-field>
|
||||
<user-file-field v-model="space.logoColorSvg" :label="$t('Logo') + ' SVG'"></user-file-field>
|
||||
<user-file-field v-model="space.customSpaceTheme" :label="$t('CustomTheme') + ' CSS'"></user-file-field>
|
||||
|
||||
|
||||
<v-btn color="success" @click="updateSpace()" prepend-icon="$save">{{ $t('Save') }}</v-btn>
|
||||
<space-editor :item-id="useUserPreferenceStore().activeSpace.id!"></space-editor>
|
||||
</v-form>
|
||||
</template>
|
||||
|
||||
|
||||
<script setup lang="ts">
|
||||
|
||||
import {useUserPreferenceStore} from "@/stores/UserPreferenceStore";
|
||||
import {onMounted, ref} from "vue";
|
||||
import {ApiApi, Space} from "@/openapi";
|
||||
import {ErrorMessageType, PreparedMessage, useMessageStore} from "@/stores/MessageStore";
|
||||
import UserFileField from "@/components/inputs/UserFileField.vue";
|
||||
import ModelSelect from "@/components/inputs/ModelSelect.vue";
|
||||
import {isSpaceAboveRecipeLimit, isSpaceAboveStorageLimit, isSpaceAboveUserLimit} from "@/utils/logic_utils";
|
||||
|
||||
const space = ref({} as Space)
|
||||
|
||||
onMounted(() => {
|
||||
let api = new ApiApi()
|
||||
api.apiSpaceCurrentRetrieve().then(r => {
|
||||
space.value = r
|
||||
}).catch(err => {
|
||||
useMessageStore().addError(ErrorMessageType.FETCH_ERROR, err)
|
||||
})
|
||||
})
|
||||
|
||||
function updateSpace() {
|
||||
let api = new ApiApi()
|
||||
api.apiSpacePartialUpdate({id: space.value.id, patchedSpace: space.value}).then(r => {
|
||||
space.value = r
|
||||
useUserPreferenceStore().activeSpace = Object.assign({}, space.value)
|
||||
useMessageStore().addPreparedMessage(PreparedMessage.UPDATE_SUCCESS, space.value)
|
||||
}).catch(err => {
|
||||
useMessageStore().addError(ErrorMessageType.UPDATE_ERROR, err)
|
||||
})
|
||||
}
|
||||
|
||||
import {useUserPreferenceStore} from "@/stores/UserPreferenceStore.ts";
|
||||
import SpaceLimitsInfo from "@/components/display/SpaceLimitsInfo.vue";
|
||||
import SpaceEditor from "@/components/model_editors/SpaceEditor.vue";
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
@@ -1,53 +0,0 @@
|
||||
<template>
|
||||
|
||||
<v-row>
|
||||
<v-col>
|
||||
<p class="text-h6">
|
||||
{{ $t('YourSpaces') }}
|
||||
<v-btn color="create" prepend-icon="$add" class="float-right" size="small" :href="getDjangoUrl('space-overview')">{{$t('New')}}</v-btn>
|
||||
</p>
|
||||
<v-divider></v-divider>
|
||||
</v-col>
|
||||
</v-row>
|
||||
|
||||
<v-row>
|
||||
<v-col cols="6" v-for="s in spaces" :key="s.id">
|
||||
<v-card @click="useUserPreferenceStore().switchSpace(s)">
|
||||
<v-img height="200px" cover :src="(s.image !== undefined) ? s.image?.preview : recipeDefaultImage" :alt="$t('Image')"></v-img>
|
||||
<v-card-title>{{ s.name }}
|
||||
<v-chip variant="tonal" density="compact" color="error" v-if="s.id == useUserPreferenceStore().activeSpace.id">{{ $t('active') }}</v-chip>
|
||||
</v-card-title>
|
||||
<v-card-subtitle>{{ $t('created_by') }} {{ s.createdBy.displayName }}</v-card-subtitle>
|
||||
</v-card>
|
||||
</v-col>
|
||||
</v-row>
|
||||
</template>
|
||||
|
||||
|
||||
<script setup lang="ts">
|
||||
|
||||
import {onMounted, ref} from "vue";
|
||||
import {ApiApi, Space} from "@/openapi";
|
||||
import {ErrorMessageType, useMessageStore} from "@/stores/MessageStore";
|
||||
import recipeDefaultImage from '../../assets/recipe_no_image.svg'
|
||||
import {useUserPreferenceStore} from "@/stores/UserPreferenceStore";
|
||||
import {useDjangoUrls} from "@/composables/useDjangoUrls";
|
||||
|
||||
const {getDjangoUrl} = useDjangoUrls()
|
||||
|
||||
const spaces = ref([] as Space[])
|
||||
|
||||
onMounted(() => {
|
||||
const api = new ApiApi()
|
||||
|
||||
api.apiSpaceList().then(r => {
|
||||
spaces.value = r.results
|
||||
}).catch(err => {
|
||||
useMessageStore().addError(ErrorMessageType.FETCH_ERROR, err)
|
||||
})
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
@@ -2,6 +2,7 @@ import {useDjangoUrls} from "@/composables/useDjangoUrls";
|
||||
import {ref} from "vue";
|
||||
import {getCookie} from "@/utils/cookie";
|
||||
import {AiProvider, RecipeFromSourceResponseFromJSON, RecipeImageFromJSON, ResponseError, UserFile, UserFileFromJSON} from "@/openapi";
|
||||
import {tr} from "vuetify/locale";
|
||||
|
||||
|
||||
/**
|
||||
@@ -117,12 +118,18 @@ export function useFileApi() {
|
||||
* @param files array to import
|
||||
* @param app app to import
|
||||
* @param includeDuplicates if recipes that were found as duplicates should be imported as well
|
||||
* @param mealPlans if meal plans should be imported
|
||||
* @param shoppingLists if shopping lists should be imported
|
||||
* @param nutritionPerServing if nutrition information should be treated as per serving (if false its treated as per recipe)
|
||||
* @returns Promise resolving to the import ID of the app import
|
||||
*/
|
||||
function doAppImport(files: File[], app: string, includeDuplicates: boolean) {
|
||||
function doAppImport(files: File[], app: string, includeDuplicates: boolean, mealPlans: boolean = true, shoppingLists: boolean = true, nutritionPerServing: boolean = false,) {
|
||||
let formData = new FormData()
|
||||
formData.append('type', app);
|
||||
formData.append('duplicates', includeDuplicates ? 'true' : 'false')
|
||||
formData.append('meal_plans', mealPlans ? 'true' : 'false')
|
||||
formData.append('shopping_lists', shoppingLists ? 'true' : 'false')
|
||||
formData.append('nutrition_per_serving', nutritionPerServing ? 'true' : 'false')
|
||||
files.forEach(file => {
|
||||
formData.append('files', file)
|
||||
})
|
||||
@@ -141,4 +148,4 @@ export function useFileApi() {
|
||||
}
|
||||
|
||||
return {fileApiLoading, createOrUpdateUserFile, updateRecipeImage, doAiImport, doAppImport}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"AISettingsHostedHelp": "",
|
||||
"API_Browser": "",
|
||||
"API_Documentation": "",
|
||||
"Active": "",
|
||||
"Add": "",
|
||||
"AddChild": "",
|
||||
"AddFoodToShopping": "",
|
||||
@@ -59,6 +60,8 @@
|
||||
"CountMore": "",
|
||||
"Create": "",
|
||||
"Create Food": "",
|
||||
"CreateFirstRecipe": "",
|
||||
"CreateInvitation": "",
|
||||
"Create_Meal_Plan_Entry": "",
|
||||
"Create_New_Food": "",
|
||||
"Create_New_Keyword": "",
|
||||
@@ -118,6 +121,7 @@
|
||||
"FuzzySearchHelp": "",
|
||||
"Global": "",
|
||||
"GlobalHelp": "",
|
||||
"Group": "",
|
||||
"GroupBy": "",
|
||||
"Hide_Food": "",
|
||||
"Hide_Keyword": "",
|
||||
@@ -133,6 +137,9 @@
|
||||
"IgnoredFood": "",
|
||||
"Image": "",
|
||||
"Import": "",
|
||||
"ImportFirstRecipe": "",
|
||||
"ImportMealPlans": "",
|
||||
"ImportShoppingList": "",
|
||||
"Import_Error": "",
|
||||
"Import_Not_Yet_Supported": "",
|
||||
"Import_Result_Info": "",
|
||||
@@ -158,6 +165,7 @@
|
||||
"Keyword": "",
|
||||
"Keyword_Alias": "",
|
||||
"Keywords": "",
|
||||
"LeaveSpace": "",
|
||||
"Link": "",
|
||||
"Load_More": "",
|
||||
"LogCredits": "",
|
||||
@@ -209,6 +217,8 @@
|
||||
"NotInShopping": "",
|
||||
"Note": "",
|
||||
"Nutrition": "",
|
||||
"NutritionsPerServing": "",
|
||||
"NutritionsPerServingHelp": "",
|
||||
"OfflineAlert": "",
|
||||
"Ok": "",
|
||||
"OnHand": "",
|
||||
@@ -284,8 +294,13 @@
|
||||
"Show_as_header": "",
|
||||
"Single": "",
|
||||
"Size": "",
|
||||
"Skip": "",
|
||||
"Sort_by_new": "",
|
||||
"Space": "",
|
||||
"SpaceHelp": "",
|
||||
"SpaceMembersHelp": "",
|
||||
"SpaceName": "",
|
||||
"SpacePrivateObjectsHelp": "",
|
||||
"Starting_Day": "",
|
||||
"StartsWith": "",
|
||||
"StartsWithHelp": "",
|
||||
@@ -332,6 +347,8 @@
|
||||
"Website": "",
|
||||
"Week": "",
|
||||
"Week_Numbers": "",
|
||||
"WelcomeSettingsHelp": "",
|
||||
"WelcometoTandoor": "",
|
||||
"Year": "",
|
||||
"Yes": "",
|
||||
"add_keyword": "",
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"AISettingsHostedHelp": "",
|
||||
"API_Browser": "",
|
||||
"API_Documentation": "",
|
||||
"Active": "",
|
||||
"Add": "Добави",
|
||||
"AddChild": "",
|
||||
"AddFoodToShopping": "Добавете {food} към списъка си за пазаруване",
|
||||
@@ -57,6 +58,8 @@
|
||||
"CountMore": "...+{count} още",
|
||||
"Create": "Създаване",
|
||||
"Create Food": "Създайте храна",
|
||||
"CreateFirstRecipe": "",
|
||||
"CreateInvitation": "",
|
||||
"Create_Meal_Plan_Entry": "Създайте запис за план за хранене",
|
||||
"Create_New_Food": "Добавете нова храна",
|
||||
"Create_New_Keyword": "Добавяне на нова ключова дума",
|
||||
@@ -115,6 +118,7 @@
|
||||
"FuzzySearchHelp": "",
|
||||
"Global": "",
|
||||
"GlobalHelp": "",
|
||||
"Group": "",
|
||||
"GroupBy": "Групирай по",
|
||||
"Hide_Food": "Скриване на храна",
|
||||
"Hide_Keyword": "Скриване на ключови думи",
|
||||
@@ -130,6 +134,9 @@
|
||||
"IgnoredFood": "{food} е настроен да игнорира пазаруването.",
|
||||
"Image": "Изображение",
|
||||
"Import": "Импортиране",
|
||||
"ImportFirstRecipe": "",
|
||||
"ImportMealPlans": "",
|
||||
"ImportShoppingList": "",
|
||||
"Import_Error": "Възникна грешка по време на импортирането ви. Моля, разгънете подробностите в долната част на страницата, за да ги видите.",
|
||||
"Import_Not_Yet_Supported": "Импортирането все още не се поддържа",
|
||||
"Import_Result_Info": "Импортирани са {imported} от {total} рецепти",
|
||||
@@ -153,6 +160,7 @@
|
||||
"Keyword": "Ключова дума",
|
||||
"Keyword_Alias": "Псевдоним на ключова дума",
|
||||
"Keywords": "Ключови думи",
|
||||
"LeaveSpace": "",
|
||||
"Link": "Връзка",
|
||||
"Load_More": "Зареди още",
|
||||
"LogCredits": "",
|
||||
@@ -202,6 +210,8 @@
|
||||
"NotInShopping": "{food} не е в списъка ви за пазаруване.",
|
||||
"Note": "Бележка",
|
||||
"Nutrition": "Хранителни стойности",
|
||||
"NutritionsPerServing": "",
|
||||
"NutritionsPerServingHelp": "",
|
||||
"OfflineAlert": "Вие сте офлайн, списъкът за пазаруване може да не се синхронизира.",
|
||||
"Ok": "Отвори",
|
||||
"OnHand": "В момента под ръка",
|
||||
@@ -277,8 +287,13 @@
|
||||
"Show_as_header": "Показване като заглавка",
|
||||
"Single": "Единичен",
|
||||
"Size": "Размер",
|
||||
"Skip": "",
|
||||
"Sort_by_new": "Сортиране по ново",
|
||||
"Space": "",
|
||||
"SpaceHelp": "",
|
||||
"SpaceMembersHelp": "",
|
||||
"SpaceName": "",
|
||||
"SpacePrivateObjectsHelp": "",
|
||||
"Starting_Day": "Начален ден от седмицата",
|
||||
"StartsWith": "",
|
||||
"StartsWithHelp": "",
|
||||
@@ -323,6 +338,8 @@
|
||||
"Website": "уебсайт",
|
||||
"Week": "Седмица",
|
||||
"Week_Numbers": "Номера на седмиците",
|
||||
"WelcomeSettingsHelp": "",
|
||||
"WelcometoTandoor": "",
|
||||
"Year": "Година",
|
||||
"Yes": "",
|
||||
"add_keyword": "Добавяне на ключова дума",
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
"API_Browser": "",
|
||||
"API_Documentation": "",
|
||||
"Account": "Compte",
|
||||
"Active": "",
|
||||
"Add": "Afegir",
|
||||
"AddChild": "",
|
||||
"AddFoodToShopping": "Afegeix {food} a la llista de la compra",
|
||||
@@ -74,6 +75,8 @@
|
||||
"Create": "Crear",
|
||||
"Create Food": "Crear aliment/ingredient",
|
||||
"Create Recipe": "Crear una recepta",
|
||||
"CreateFirstRecipe": "",
|
||||
"CreateInvitation": "",
|
||||
"Create_Meal_Plan_Entry": "Crear una entrada de la planificació d'àpats",
|
||||
"Create_New_Food": "Afegir nou ingredient",
|
||||
"Create_New_Keyword": "Afegir nova Paraula Clau",
|
||||
@@ -159,6 +162,7 @@
|
||||
"FuzzySearchHelp": "",
|
||||
"Global": "",
|
||||
"GlobalHelp": "",
|
||||
"Group": "",
|
||||
"GroupBy": "Agrupat per",
|
||||
"Hide_Food": "Amagar Aliment",
|
||||
"Hide_Keyword": "Amaga les paraules clau",
|
||||
@@ -177,6 +181,9 @@
|
||||
"Image": "Imatge",
|
||||
"Import": "Importar",
|
||||
"Import Recipe": "Importar Recepta",
|
||||
"ImportFirstRecipe": "",
|
||||
"ImportMealPlans": "",
|
||||
"ImportShoppingList": "",
|
||||
"Import_Error": "S'ha produït un error durant la importació. Si us plau, amplia els detalls a la part inferior de la pàgina per veure'l.",
|
||||
"Import_Not_Yet_Supported": "Importació encara no suportada",
|
||||
"Import_Result_Info": "{imported} de {total} receptes s'han importat",
|
||||
@@ -207,6 +214,7 @@
|
||||
"Language": "Llenguatge",
|
||||
"Last_name": "Cognoms",
|
||||
"Learn_More": "Saber-me més",
|
||||
"LeaveSpace": "",
|
||||
"Link": "Enllaç",
|
||||
"Load_More": "Carregueu-ne més",
|
||||
"LogCredits": "",
|
||||
@@ -268,6 +276,8 @@
|
||||
"Note": "Nota",
|
||||
"Number of Objects": "Nombre d'Objectes",
|
||||
"Nutrition": "Valors nutricionals",
|
||||
"NutritionsPerServing": "",
|
||||
"NutritionsPerServingHelp": "",
|
||||
"OfflineAlert": "Estàs desconnectat, la llista de la compra no pot actualitzar-se.",
|
||||
"Ok": "Ok",
|
||||
"OnHand": "Ja en tinc",
|
||||
@@ -361,9 +371,14 @@
|
||||
"Show_as_header": "Mostreu com a títol",
|
||||
"Single": "Únic/a",
|
||||
"Size": "Mida",
|
||||
"Skip": "",
|
||||
"Social_Authentication": "Identificació amb Xarxes Socials",
|
||||
"Sort_by_new": "Ordenar a partir del més nou",
|
||||
"Space": "",
|
||||
"SpaceHelp": "",
|
||||
"SpaceMembersHelp": "",
|
||||
"SpaceName": "",
|
||||
"SpacePrivateObjectsHelp": "",
|
||||
"Space_Cosmetic_Settings": "Un administrador de l'espai podria canviar algunes configuracions estètiques i tindrien prioritat sobre la configuració dels usuaris per a aquest espai.",
|
||||
"Split_All_Steps": "Dividir totes les files en passos separats.",
|
||||
"StartDate": "Data d'inici",
|
||||
@@ -430,6 +445,8 @@
|
||||
"Week": "Setmana",
|
||||
"Week_Numbers": "Números de la setmana",
|
||||
"Welcome": "Benvingut/da",
|
||||
"WelcomeSettingsHelp": "",
|
||||
"WelcometoTandoor": "",
|
||||
"Year": "Any",
|
||||
"Yes": "",
|
||||
"add_keyword": "Afegir Paraula Clau",
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
"API_Browser": "",
|
||||
"API_Documentation": "",
|
||||
"Account": "Účet",
|
||||
"Active": "",
|
||||
"Add": "Přidat",
|
||||
"AddChild": "",
|
||||
"AddFoodToShopping": "Přidat {food} na váš nákupní seznam",
|
||||
@@ -74,6 +75,8 @@
|
||||
"Create": "Vytvořit",
|
||||
"Create Food": "Vytvořit potravinu",
|
||||
"Create Recipe": "Vytvořit recept",
|
||||
"CreateFirstRecipe": "",
|
||||
"CreateInvitation": "",
|
||||
"Create_Meal_Plan_Entry": "Vytvořit položku v jídelníčku",
|
||||
"Create_New_Food": "Přidat novou potravinu",
|
||||
"Create_New_Keyword": "Přidat nový štítek",
|
||||
@@ -158,6 +161,7 @@
|
||||
"FuzzySearchHelp": "",
|
||||
"Global": "",
|
||||
"GlobalHelp": "",
|
||||
"Group": "",
|
||||
"GroupBy": "Seskupit podle",
|
||||
"Hide_Food": "Skrýt potravinu",
|
||||
"Hide_Keyword": "Skrýt štítky",
|
||||
@@ -176,6 +180,9 @@
|
||||
"Image": "Obrázek",
|
||||
"Import": "Import",
|
||||
"Import Recipe": "Importovat recept",
|
||||
"ImportFirstRecipe": "",
|
||||
"ImportMealPlans": "",
|
||||
"ImportShoppingList": "",
|
||||
"Import_Error": "Během importu došlo k chybě. Pro více informací rozbalte Detaily na konci stránky.",
|
||||
"Import_Not_Yet_Supported": "Import není zatím podporován",
|
||||
"Import_Result_Info": "{imported} z {total} receptů naimportováno",
|
||||
@@ -205,6 +212,7 @@
|
||||
"Language": "Jazyk",
|
||||
"Last_name": "Příjmení",
|
||||
"Learn_More": "Zjistit víc",
|
||||
"LeaveSpace": "",
|
||||
"Link": "Odkaz",
|
||||
"Load_More": "Načíst další",
|
||||
"LogCredits": "",
|
||||
@@ -265,6 +273,8 @@
|
||||
"Note": "Poznámka",
|
||||
"Number of Objects": "Počet Objektů",
|
||||
"Nutrition": "Výživové hodnoty",
|
||||
"NutritionsPerServing": "",
|
||||
"NutritionsPerServingHelp": "",
|
||||
"OfflineAlert": "Jste offline, nákupní seznam nemusí být synchronizován.",
|
||||
"Ok": "Ok",
|
||||
"OnHand": "Momentálně k dispozici",
|
||||
@@ -356,9 +366,14 @@
|
||||
"Show_as_header": "Nastav jako nadpis",
|
||||
"Single": "Jednoduchý",
|
||||
"Size": "Velikost",
|
||||
"Skip": "",
|
||||
"Social_Authentication": "Přihlašování pomocí účtů sociálních sítí",
|
||||
"Sort_by_new": "Seřadit od nejnovějšího",
|
||||
"Space": "",
|
||||
"SpaceHelp": "",
|
||||
"SpaceMembersHelp": "",
|
||||
"SpaceName": "",
|
||||
"SpacePrivateObjectsHelp": "",
|
||||
"Space_Cosmetic_Settings": "Některá kosmetická nastavení mohou měnit správci prostoru a budou mít přednost před nastavením klienta pro daný prostor.",
|
||||
"Split_All_Steps": "Rozdělit každý řádek do samostatného kroku.",
|
||||
"StartDate": "Počáteční datum",
|
||||
@@ -422,6 +437,8 @@
|
||||
"Week": "Týden",
|
||||
"Week_Numbers": "Číslo týdne",
|
||||
"Welcome": "Vítejte",
|
||||
"WelcomeSettingsHelp": "",
|
||||
"WelcometoTandoor": "",
|
||||
"Year": "Rok",
|
||||
"Yes": "",
|
||||
"add_keyword": "Přidat štítek",
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
"API_Browser": "",
|
||||
"API_Documentation": "",
|
||||
"Account": "Bruger",
|
||||
"Active": "",
|
||||
"Add": "Tilføj",
|
||||
"AddChild": "",
|
||||
"AddFoodToShopping": "Tilføj {food} til indkøbsliste",
|
||||
@@ -74,6 +75,8 @@
|
||||
"Create": "Opret",
|
||||
"Create Food": "Opret mad",
|
||||
"Create Recipe": "Opret opskrift",
|
||||
"CreateFirstRecipe": "",
|
||||
"CreateInvitation": "",
|
||||
"Create_Meal_Plan_Entry": "Indsæt punkt i madplan",
|
||||
"Create_New_Food": "Tilføj ny mad",
|
||||
"Create_New_Keyword": "Tilføj nyt nøgleord",
|
||||
@@ -159,6 +162,7 @@
|
||||
"FuzzySearchHelp": "",
|
||||
"Global": "",
|
||||
"GlobalHelp": "",
|
||||
"Group": "",
|
||||
"GroupBy": "Grupper efter",
|
||||
"Hide_Food": "Skjul mad",
|
||||
"Hide_Keyword": "Skjul nøgleord",
|
||||
@@ -177,6 +181,9 @@
|
||||
"Image": "Billede",
|
||||
"Import": "Importer",
|
||||
"Import Recipe": "Importer opskrift",
|
||||
"ImportFirstRecipe": "",
|
||||
"ImportMealPlans": "",
|
||||
"ImportShoppingList": "",
|
||||
"Import_Error": "Der opstod en fejl under din importering. Udvid detaljerne i bunden af siden for at se fejlen.",
|
||||
"Import_Not_Yet_Supported": "Import endnu ikke understøttet",
|
||||
"Import_Result_Info": "{imported} af {total} opskrifter blev importeret",
|
||||
@@ -207,6 +214,7 @@
|
||||
"Language": "Sprog",
|
||||
"Last_name": "Efternavn",
|
||||
"Learn_More": "Lær mere",
|
||||
"LeaveSpace": "",
|
||||
"Link": "Link",
|
||||
"Load_More": "Indlæs mere",
|
||||
"LogCredits": "",
|
||||
@@ -268,6 +276,8 @@
|
||||
"Note": "Note",
|
||||
"Number of Objects": "Antal objekter",
|
||||
"Nutrition": "Næring",
|
||||
"NutritionsPerServing": "",
|
||||
"NutritionsPerServingHelp": "",
|
||||
"OfflineAlert": "Du er offline, indkøbslisten er måske ikke synkroniseret.",
|
||||
"Ok": "Åben",
|
||||
"OnHand": "Til rådighed",
|
||||
@@ -361,9 +371,14 @@
|
||||
"Show_as_header": "Vis som rubrik",
|
||||
"Single": "Enkel",
|
||||
"Size": "Størrelse",
|
||||
"Skip": "",
|
||||
"Social_Authentication": "Social authenticering",
|
||||
"Sort_by_new": "Sorter efter nylige",
|
||||
"Space": "",
|
||||
"SpaceHelp": "",
|
||||
"SpaceMembersHelp": "",
|
||||
"SpaceName": "",
|
||||
"SpacePrivateObjectsHelp": "",
|
||||
"Space_Cosmetic_Settings": "Visse kosmetiske indstillinger kan ændres af område-administratorer og vil overskrive klient-indstillinger for pågældende område.",
|
||||
"Split_All_Steps": "Opdel rækker i separate trin.",
|
||||
"StartDate": "Startdato",
|
||||
@@ -430,6 +445,8 @@
|
||||
"Week": "Uge",
|
||||
"Week_Numbers": "Ugenumre",
|
||||
"Welcome": "Velkommen",
|
||||
"WelcomeSettingsHelp": "",
|
||||
"WelcometoTandoor": "",
|
||||
"Year": "År",
|
||||
"Yes": "",
|
||||
"add_keyword": "Tilføj nøgleord",
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
"Access_Token": "Zugriffstoken",
|
||||
"Account": "Konto",
|
||||
"Actions": "Aktionen",
|
||||
"Active": "Aktiv",
|
||||
"Activity": "Aktivität",
|
||||
"Add": "Hinzufügen",
|
||||
"AddAll": "Alle Hinzufügen",
|
||||
@@ -111,6 +112,8 @@
|
||||
"Create": "Erstellen",
|
||||
"Create Food": "Zutat erstellen",
|
||||
"Create Recipe": "Rezept erstellen",
|
||||
"CreateFirstRecipe": "Erstelle dein erstes Rezept mit dem Rezepteditor.",
|
||||
"CreateInvitation": "Einladung erstellen",
|
||||
"Create_Meal_Plan_Entry": "Neuer Eintrag",
|
||||
"Create_New_Food": "Neues Lebensmittel hinzufügen",
|
||||
"Create_New_Keyword": "Neues Schlagwort hinzufügen",
|
||||
@@ -222,6 +225,7 @@
|
||||
"GettingStarted": "Erste Schritte",
|
||||
"Global": "Global",
|
||||
"GlobalHelp": "Globale AI Anbieter können von Nutzern aller Spaces verwendet werden. Sie können nur dich Instanz Admins (Superusers) erstellt und bearbeitet werden.",
|
||||
"Group": "Gruppe",
|
||||
"GroupBy": "Gruppieren nach",
|
||||
"HeaderWarning": "Achtung: Durch ändern auf Überschrift werden Menge/Einheit/Lebensmittel gelöscht",
|
||||
"Headline": "Überschrift",
|
||||
@@ -247,7 +251,10 @@
|
||||
"Import": "Importieren",
|
||||
"Import Recipe": "Rezept importieren",
|
||||
"ImportAll": "Alle importieren",
|
||||
"ImportFirstRecipe": "Importiere dein erstes Rezept von einer von tausenden Websites oder nutze einen der anderen Importer um bestehende Sammlungen, Dokumente oder URL Listen zu importieren. ",
|
||||
"ImportIntoTandoor": "In Tandoor importieren",
|
||||
"ImportMealPlans": "Speisepläne importieren",
|
||||
"ImportShoppingList": "Einkaufslisten importieren",
|
||||
"Import_Error": "Es ist ein Fehler beim Importieren aufgetreten. Bitte sieh dir die ausgeklappten Details unten auf der Seite an.",
|
||||
"Import_Not_Yet_Supported": "Importieren wird noch nicht unterstützt",
|
||||
"Import_Result_Info": "{imported} von insgesamt {total} Rezepten wurden importiert",
|
||||
@@ -286,6 +293,7 @@
|
||||
"Last": "Letztes",
|
||||
"Last_name": "Nachname",
|
||||
"Learn_More": "Mehr erfahren",
|
||||
"LeaveSpace": "Space verlassen",
|
||||
"Link": "Link",
|
||||
"Load": "Laden",
|
||||
"Load_More": "Weitere laden",
|
||||
@@ -363,6 +371,8 @@
|
||||
"Note": "Notiz",
|
||||
"Number of Objects": "Anzahl von Objekten",
|
||||
"Nutrition": "Nährwerte",
|
||||
"NutritionsPerServing": "Nährwerte pro Portion",
|
||||
"NutritionsPerServingHelp": "Manche Anwendungen spezifizieren nicht, ob Nährwerte pro Portion oder pro Rezept anzugeben sind. Standardmäßig werden Sie daher pro Rezept importiert. Wähle diese Option um Sie als pro Portion zu behandeln.",
|
||||
"OfflineAlert": "Du bist offline. Deine Einkaufsliste wird nicht synchronisiert.",
|
||||
"Ok": "Ok",
|
||||
"OnHand": "Aktuell vorrätig",
|
||||
@@ -499,17 +509,21 @@
|
||||
"Show_as_header": "Als Überschrift",
|
||||
"Single": "Einzeln",
|
||||
"Size": "Größe",
|
||||
"Skip": "Überspringen",
|
||||
"Social_Authentication": "Login über Drittanbieter",
|
||||
"Sort_by_new": "Nach Neueste sortieren",
|
||||
"Source": "Quelle",
|
||||
"SourceImportHelp": "Importiere JSON im schema.org/recipe format oder eine HTML Seite mit json+ld Rezept bzw. microdata.",
|
||||
"SourceImportSubtitle": "Importiere JSON oder HTML manuell.",
|
||||
"Space": "Space",
|
||||
"SpaceHelp": "Alle deine Daten sind sicher in deinem Space gespeichert und können nur von dir und den anderen Mitgliedern genutzt werden.",
|
||||
"SpaceLimitExceeded": "Dein Space hat ein Limit überschritten, manche Funktionen wurden eingeschränkt.",
|
||||
"SpaceLimitReached": "Dieser Space hat ein Limit erreicht. Es können keine neuen Objekte von diesem Typ angelegt werden.",
|
||||
"SpaceMemberHelp": "Füge Benutzer hinzu indem du Einladungen erstellst und Sie an die gewünschte Person sendest.",
|
||||
"SpaceMembers": "Space Mitglieder",
|
||||
"SpaceMembersHelp": "Benutzer und Ihre Rechte in einem Space. ",
|
||||
"SpaceMembersHelp": "Benutzer und Ihre Rechte in einem Space. Füge weitere Nutzer mit Einladungslinks hinzu.",
|
||||
"SpaceName": "Space Name",
|
||||
"SpacePrivateObjectsHelp": "Einige Objekte sind Standardmäßig privat, können aber mit Mitgliedern deines Spaces geteilt werden.",
|
||||
"SpaceSettings": "Space Einstellungen",
|
||||
"Space_Cosmetic_Settings": "Kosmetische Einstellungen auf Space Ebene überschreiben die Einstellungen der einzelnen Nutzer.",
|
||||
"Split": "Aufteilen",
|
||||
@@ -621,6 +635,8 @@
|
||||
"Week": "Woche",
|
||||
"Week_Numbers": "Kalenderwochen",
|
||||
"Welcome": "Willkommen",
|
||||
"WelcomeSettingsHelp": "Bitte wähle die grundlegenden Einstellungen für deinen Space. Du kannst Sie später jederzeit in den Einstellungen ändern.",
|
||||
"WelcometoTandoor": "Willkommen bei Tandoor",
|
||||
"WorkingTime": "Arbeitszeit",
|
||||
"Year": "Jahr",
|
||||
"Yes": "Ja",
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
"API_Browser": "",
|
||||
"API_Documentation": "",
|
||||
"Account": "Λογαριασμός",
|
||||
"Active": "",
|
||||
"Add": "Προσθήκη",
|
||||
"AddChild": "",
|
||||
"AddFoodToShopping": "Προσθήκη του φαγητού {food} στη λίστα αγορών σας",
|
||||
@@ -74,6 +75,8 @@
|
||||
"Create": "Δημιουργία",
|
||||
"Create Food": "Δημιουργία φαγητού",
|
||||
"Create Recipe": "Δημιουργία συνταγής",
|
||||
"CreateFirstRecipe": "",
|
||||
"CreateInvitation": "",
|
||||
"Create_Meal_Plan_Entry": "Δημιουργία εγγραφής στο πρόγραμμα γευμάτων",
|
||||
"Create_New_Food": "Προσθήκη νέου φαγητού",
|
||||
"Create_New_Keyword": "Προσθήκη νέας λέξης-κλειδί",
|
||||
@@ -159,6 +162,7 @@
|
||||
"FuzzySearchHelp": "",
|
||||
"Global": "",
|
||||
"GlobalHelp": "",
|
||||
"Group": "",
|
||||
"GroupBy": "Ομαδοποίηση κατά",
|
||||
"Hide_Food": "Απόκρυψη φαγητού",
|
||||
"Hide_Keyword": "Απόκρυψη λέξεων-κλειδί",
|
||||
@@ -177,6 +181,9 @@
|
||||
"Image": "Εικόνα",
|
||||
"Import": "Εισαγωγή",
|
||||
"Import Recipe": "Εισαγωγή συνταγής",
|
||||
"ImportFirstRecipe": "",
|
||||
"ImportMealPlans": "",
|
||||
"ImportShoppingList": "",
|
||||
"Import_Error": "Συνέβη ένα σφάλμα κατά την εισαγωγή. Για να το δείτε, εμφανίστε τις λεπτομέρειες στο κάτω μέρος της σελίδας.",
|
||||
"Import_Not_Yet_Supported": "Η εισαγωγή δεν υποστηρίζεται ακόμη",
|
||||
"Import_Result_Info": "Έγινε εισαγωγή {imported} από τις {total} συνταγές",
|
||||
@@ -207,6 +214,7 @@
|
||||
"Language": "Γλώσσα",
|
||||
"Last_name": "Επίθετο",
|
||||
"Learn_More": "Μάθετε περισσότερα",
|
||||
"LeaveSpace": "",
|
||||
"Link": "Σύνδεσμος",
|
||||
"Load_More": "Φόρτωση περισσότερων",
|
||||
"LogCredits": "",
|
||||
@@ -268,6 +276,8 @@
|
||||
"Note": "Σημείωση",
|
||||
"Number of Objects": "Αριθμός αντικειμένων",
|
||||
"Nutrition": "Διατροφική αξία",
|
||||
"NutritionsPerServing": "",
|
||||
"NutritionsPerServingHelp": "",
|
||||
"OfflineAlert": "Είστε εκτός σύνδεσης, η λίστα αγορών μπορεί να μην συγχρονιστεί.",
|
||||
"Ok": "ΟΚ",
|
||||
"OnHand": "Τώρα διαθέσιμα",
|
||||
@@ -361,9 +371,14 @@
|
||||
"Show_as_header": "Εμφάνιση ως κεφαλίδα",
|
||||
"Single": "Ενικός",
|
||||
"Size": "Μέγεθος",
|
||||
"Skip": "",
|
||||
"Social_Authentication": "Ταυτοποίηση μέσω κοινωνικών δικτύων",
|
||||
"Sort_by_new": "Ταξινόμηση κατά νέο",
|
||||
"Space": "",
|
||||
"SpaceHelp": "",
|
||||
"SpaceMembersHelp": "",
|
||||
"SpaceName": "",
|
||||
"SpacePrivateObjectsHelp": "",
|
||||
"Space_Cosmetic_Settings": "Ορισμένες ρυθμίσεις εμφάνισης μπορούν να αλλάξουν από τους διαχειριστές του χώρου και θα παρακάμψουν τις ρυθμίσεις πελάτη για αυτόν τον χώρο.",
|
||||
"Split_All_Steps": "Διαχωρισμός όλων των γραμμών σε χωριστά βήματα.",
|
||||
"StartDate": "Ημερομηνία Έναρξης",
|
||||
@@ -430,6 +445,8 @@
|
||||
"Week": "Εβδομάδα",
|
||||
"Week_Numbers": "Αριθμοί εδομάδων",
|
||||
"Welcome": "Καλώς ήρθατε",
|
||||
"WelcomeSettingsHelp": "",
|
||||
"WelcometoTandoor": "",
|
||||
"Year": "Έτος",
|
||||
"Yes": "",
|
||||
"add_keyword": "Προσθήκη λέξης-κλειδί",
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
"Access_Token": "Access Token",
|
||||
"Account": "Account",
|
||||
"Actions": "Actions",
|
||||
"Active": "Active",
|
||||
"Activity": "Activity",
|
||||
"Add": "Add",
|
||||
"AddAll": "Add all",
|
||||
@@ -109,6 +110,8 @@
|
||||
"Create": "Create",
|
||||
"Create Food": "Create Food",
|
||||
"Create Recipe": "Create Recipe",
|
||||
"CreateFirstRecipe": "Create your first recipe using the recipe editor.",
|
||||
"CreateInvitation": "Create invitation",
|
||||
"Create_Meal_Plan_Entry": "Create meal plan entry",
|
||||
"Create_New_Food": "Add New Food",
|
||||
"Create_New_Keyword": "Add New Keyword",
|
||||
@@ -220,6 +223,7 @@
|
||||
"GettingStarted": "Getting Started",
|
||||
"Global": "Global",
|
||||
"GlobalHelp": "Global AI Providers can be used by users of all spaces. They can only be created and edited by superusers. ",
|
||||
"Group": "Group",
|
||||
"GroupBy": "Group By",
|
||||
"HeaderWarning": "Warning: Changing to a Heading deletes the Amount/Unit/Food",
|
||||
"Headline": "Headline",
|
||||
@@ -245,7 +249,10 @@
|
||||
"Import": "Import",
|
||||
"Import Recipe": "Import Recipe",
|
||||
"ImportAll": "Import all",
|
||||
"ImportFirstRecipe": "Import your first recipe from one of thousands of websites or use one of the other importers to import your existing collection, documents or URL lists.",
|
||||
"ImportIntoTandoor": "Import into Tandoor",
|
||||
"ImportMealPlans": "Import mealplans",
|
||||
"ImportShoppingList": "Import shoppinglists",
|
||||
"Import_Error": "An Error occurred during your import. Please expand the Details at the bottom of the page to view it.",
|
||||
"Import_Not_Yet_Supported": "Import not yet supported",
|
||||
"Import_Result_Info": "{imported} of {total} recipes were imported",
|
||||
@@ -284,6 +291,7 @@
|
||||
"Last": "Last",
|
||||
"Last_name": "Last Name",
|
||||
"Learn_More": "Learn More",
|
||||
"LeaveSpace": "Leave Space",
|
||||
"Link": "Link",
|
||||
"Load": "Load",
|
||||
"Load_More": "Load More",
|
||||
@@ -361,6 +369,8 @@
|
||||
"Note": "Note",
|
||||
"Number of Objects": "Number of Objects",
|
||||
"Nutrition": "Nutrition",
|
||||
"NutritionsPerServing": "Nutritions per Serving",
|
||||
"NutritionsPerServingHelp": "Some applications do not specify if nutritions are per recipe or per serving. By default Tandoor treats them as per recipe. Check this box to treat them as per serving. ",
|
||||
"OfflineAlert": "You are offline, shopping list may not syncronize.",
|
||||
"Ok": "Ok",
|
||||
"OnHand": "Currently On Hand",
|
||||
@@ -497,17 +507,21 @@
|
||||
"Show_as_header": "Show as header",
|
||||
"Single": "Single",
|
||||
"Size": "Size",
|
||||
"Skip": "Skip",
|
||||
"Social_Authentication": "Social Authentication",
|
||||
"Sort_by_new": "Sort by new",
|
||||
"Source": "Source",
|
||||
"SourceImportHelp": "Import JSON in schema.org/recipe format or html pages with json+ld recipe or microdata.",
|
||||
"SourceImportSubtitle": "Import JSON or HTML manually.",
|
||||
"Space": "Space",
|
||||
"SpaceHelp": "All your data is part of your space and can only be acccessed by space members. ",
|
||||
"SpaceLimitExceeded": "Your space has surpassed one of its limits, some functions might be restricted.",
|
||||
"SpaceLimitReached": "This Space has reached a limit. No more objects of this type can be created.",
|
||||
"SpaceMemberHelp": "Add users to your space by creating an Invite Link and sending it to the person you want to add.",
|
||||
"SpaceMembers": "Space Members",
|
||||
"SpaceMembersHelp": "Users and their permissions in a space. ",
|
||||
"SpaceMembersHelp": "Users and their permissions in a space. Add additional users using invite links.",
|
||||
"SpaceName": "Space Name",
|
||||
"SpacePrivateObjectsHelp": " Some things are private by default an can be shared with members of your space.",
|
||||
"SpaceSettings": "Space Settings",
|
||||
"Space_Cosmetic_Settings": "Some cosmetic settings can be changed by space administrators and will override client settings for that space.",
|
||||
"Split": "Split",
|
||||
@@ -619,6 +633,8 @@
|
||||
"Week": "Week",
|
||||
"Week_Numbers": "Week numbers",
|
||||
"Welcome": "Welcome",
|
||||
"WelcomeSettingsHelp": "Please choose the basic settings for your Tandoor space. You can change all of these later trough the settings.",
|
||||
"WelcometoTandoor": "Welcome to Tandoor",
|
||||
"WorkingTime": "Working time",
|
||||
"Year": "Year",
|
||||
"Yes": "Yes",
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
"Access_Token": "Token de acceso",
|
||||
"Account": "Cuenta",
|
||||
"Actions": "Acciones",
|
||||
"Active": "",
|
||||
"Activity": "Actividad",
|
||||
"Add": "Añadir",
|
||||
"AddAll": "Agregar todo",
|
||||
@@ -106,6 +107,8 @@
|
||||
"Create": "Crear",
|
||||
"Create Food": "Crear alimento",
|
||||
"Create Recipe": "Crear receta",
|
||||
"CreateFirstRecipe": "",
|
||||
"CreateInvitation": "",
|
||||
"Create_Meal_Plan_Entry": "Crear entrada de plan de comidas",
|
||||
"Create_New_Food": "Añadir nuevo alimento",
|
||||
"Create_New_Keyword": "Añadir nueva palabra clave",
|
||||
@@ -213,6 +216,7 @@
|
||||
"GettingStarted": "Primeros pasos",
|
||||
"Global": "",
|
||||
"GlobalHelp": "",
|
||||
"Group": "",
|
||||
"GroupBy": "Agrupar por",
|
||||
"HeaderWarning": "Advertencia: Cambiar a un encabezado eliminará la cantidad/unidad/alimento",
|
||||
"Headline": "Encabezado",
|
||||
@@ -236,7 +240,10 @@
|
||||
"Import": "Importar",
|
||||
"Import Recipe": "Importar Receta",
|
||||
"ImportAll": "Importar todo",
|
||||
"ImportFirstRecipe": "",
|
||||
"ImportIntoTandoor": "Importar a Tandoor",
|
||||
"ImportMealPlans": "",
|
||||
"ImportShoppingList": "",
|
||||
"Import_Error": "Ocurrió un Error ocurrió durante la importación. Por favor, expanda los Detalles al final de la página para verlo.",
|
||||
"Import_Not_Yet_Supported": "Importación no soportada todavía",
|
||||
"Import_Result_Info": "{imported} de {total} recetas fueron importadas",
|
||||
@@ -275,6 +282,7 @@
|
||||
"Last": "Último",
|
||||
"Last_name": "Apellidos",
|
||||
"Learn_More": "Saber Más",
|
||||
"LeaveSpace": "",
|
||||
"Link": "Enlace",
|
||||
"Load": "Cargar",
|
||||
"Load_More": "Cargar más",
|
||||
@@ -351,6 +359,8 @@
|
||||
"Note": "Nota",
|
||||
"Number of Objects": "Número de Objetos",
|
||||
"Nutrition": "Nutrición",
|
||||
"NutritionsPerServing": "",
|
||||
"NutritionsPerServingHelp": "",
|
||||
"OfflineAlert": "Estas desconectado, la lista de la compra puede no sincronizarse.",
|
||||
"Ok": "Ok",
|
||||
"OnHand": "Actualmente en Posesión",
|
||||
@@ -480,16 +490,20 @@
|
||||
"Show_as_header": "Mostrar como encabezado",
|
||||
"Single": "Simple",
|
||||
"Size": "Tamaño",
|
||||
"Skip": "",
|
||||
"Social_Authentication": "Autenticación Social",
|
||||
"Sort_by_new": "Ordenar por novedades",
|
||||
"SourceImportHelp": "Importar JSON en formato schema.org/recipe o páginas HTML con recetas en formato JSON+LD o microdatos.",
|
||||
"SourceImportSubtitle": "Importar JSON o HTML manualmente.",
|
||||
"Space": "",
|
||||
"SpaceHelp": "",
|
||||
"SpaceLimitExceeded": "Tu espacio ha sobrepasado uno de sus límites, algunas funciones podrían estar restringidas.",
|
||||
"SpaceLimitReached": "Este espacio ha alcanzado un límite. No se pueden crear más objetos de este tipo.",
|
||||
"SpaceMemberHelp": "Agrega usuarios a tu espacio creando un enlace de invitación y enviándolo a la persona que quieras agregar.",
|
||||
"SpaceMembers": "Miembros del espacio",
|
||||
"SpaceMembersHelp": "Usuarios y sus permisos en un espacio. ",
|
||||
"SpaceMembersHelp": "",
|
||||
"SpaceName": "",
|
||||
"SpacePrivateObjectsHelp": "",
|
||||
"SpaceSettings": "Ajustes del espacio",
|
||||
"Space_Cosmetic_Settings": "Algunos ajustes de apariencia pueden ser cambiados por los administradores del espacio y anularán los ajustes del cliente para ese espacio.",
|
||||
"Split": "Dividir",
|
||||
@@ -595,6 +609,8 @@
|
||||
"Week": "Semana",
|
||||
"Week_Numbers": "numero de semana",
|
||||
"Welcome": "Bienvenido/a",
|
||||
"WelcomeSettingsHelp": "",
|
||||
"WelcometoTandoor": "",
|
||||
"WorkingTime": "Tiempo de trabajo",
|
||||
"Year": "Año",
|
||||
"Yes": "",
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
"API_Browser": "",
|
||||
"API_Documentation": "",
|
||||
"Account": "Tili",
|
||||
"Active": "",
|
||||
"Add": "Lisää",
|
||||
"AddChild": "",
|
||||
"AddFoodToShopping": "Lisää {food} ostoslistaan",
|
||||
@@ -71,6 +72,8 @@
|
||||
"CountMore": "...+{count} enemmän",
|
||||
"Create": "Luo",
|
||||
"Create Food": "Luo Ruoka",
|
||||
"CreateFirstRecipe": "",
|
||||
"CreateInvitation": "",
|
||||
"Create_Meal_Plan_Entry": "Luo ateriasuunnitelma merkintä",
|
||||
"Create_New_Food": "Lisää Uusi Ruoka",
|
||||
"Create_New_Keyword": "Lisää Uusi Avainsana",
|
||||
@@ -156,6 +159,7 @@
|
||||
"FuzzySearchHelp": "",
|
||||
"Global": "",
|
||||
"GlobalHelp": "",
|
||||
"Group": "",
|
||||
"GroupBy": "Ryhmittely peruste",
|
||||
"Hide_Food": "Piilota Ruoka",
|
||||
"Hide_Keyword": "Piilota avainsana",
|
||||
@@ -174,6 +178,9 @@
|
||||
"Image": "Kuva",
|
||||
"Import": "Tuo",
|
||||
"Import Recipe": "Tuo Resepti",
|
||||
"ImportFirstRecipe": "",
|
||||
"ImportMealPlans": "",
|
||||
"ImportShoppingList": "",
|
||||
"Import_Not_Yet_Supported": "Tuontia ei vielä tueta",
|
||||
"Import_Supported": "Tuonti tuettu",
|
||||
"Import_finished": "Tuonti valmistui",
|
||||
@@ -201,6 +208,7 @@
|
||||
"Language": "Kieli",
|
||||
"Last_name": "Sukunimi",
|
||||
"Learn_More": "Lisätietoja",
|
||||
"LeaveSpace": "",
|
||||
"Link": "Linkki",
|
||||
"Load_More": "Lataa Lisää",
|
||||
"LogCredits": "",
|
||||
@@ -257,6 +265,8 @@
|
||||
"Note": "Lisätiedot",
|
||||
"Number of Objects": "Objektien määrä",
|
||||
"Nutrition": "Ravitsemus",
|
||||
"NutritionsPerServing": "",
|
||||
"NutritionsPerServingHelp": "",
|
||||
"OfflineAlert": "Olet offline-tilassa, ostoslista ei välttämättä synkronoidu.",
|
||||
"Ok": "Ok",
|
||||
"OnHand": "Tällä hetkellä saatavilla",
|
||||
@@ -349,9 +359,14 @@
|
||||
"Show_as_header": "Näytä otsikkona",
|
||||
"Single": "Yksittäinen",
|
||||
"Size": "Koko",
|
||||
"Skip": "",
|
||||
"Social_Authentication": "Sosiaalinen Todennus",
|
||||
"Sort_by_new": "Lajittele uusien mukaan",
|
||||
"Space": "",
|
||||
"SpaceHelp": "",
|
||||
"SpaceMembersHelp": "",
|
||||
"SpaceName": "",
|
||||
"SpacePrivateObjectsHelp": "",
|
||||
"Split_All_Steps": "Jaa kaikki rivit erillisiin vaiheisiin.",
|
||||
"StartDate": "Aloituspäivä",
|
||||
"Starting_Day": "Viikon aloituspäivä",
|
||||
@@ -410,6 +425,8 @@
|
||||
"Week": "Viikko",
|
||||
"Week_Numbers": "Viikkonumerot",
|
||||
"Welcome": "Tervetuloa",
|
||||
"WelcomeSettingsHelp": "",
|
||||
"WelcometoTandoor": "",
|
||||
"Year": "Vuosi",
|
||||
"Yes": "",
|
||||
"add_keyword": "Lisää Avainsana",
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
"Access_Token": "Jeton d'accès",
|
||||
"Account": "Compte",
|
||||
"Actions": "Actions",
|
||||
"Active": "",
|
||||
"Activity": "Activité",
|
||||
"Add": "Ajouter",
|
||||
"AddAll": "Tout ajouter",
|
||||
@@ -109,6 +110,8 @@
|
||||
"Create": "Créer",
|
||||
"Create Food": "Créer un aliment",
|
||||
"Create Recipe": "Créer une recette",
|
||||
"CreateFirstRecipe": "",
|
||||
"CreateInvitation": "",
|
||||
"Create_Meal_Plan_Entry": "Créer une entrée de menu",
|
||||
"Create_New_Food": "Ajouter un nouvel aliment",
|
||||
"Create_New_Keyword": "Ajouter un nouveau mot-clé",
|
||||
@@ -220,6 +223,7 @@
|
||||
"GettingStarted": "Commencer",
|
||||
"Global": "",
|
||||
"GlobalHelp": "",
|
||||
"Group": "",
|
||||
"GroupBy": "Grouper par",
|
||||
"HeaderWarning": "Attention : Changer pour un En-tête supprimera la quantité / l'unité / l'aliment",
|
||||
"Headline": "En-tête",
|
||||
@@ -245,7 +249,10 @@
|
||||
"Import": "Importer",
|
||||
"Import Recipe": "Importer une recette",
|
||||
"ImportAll": "Tout importer",
|
||||
"ImportFirstRecipe": "",
|
||||
"ImportIntoTandoor": "Importer dans Tandoor",
|
||||
"ImportMealPlans": "",
|
||||
"ImportShoppingList": "",
|
||||
"Import_Error": "Une erreur est survenue pendant votre importation. Veuillez développer les détails au bas de la page pour la consulter.",
|
||||
"Import_Not_Yet_Supported": "Importation pas encore prise en charge",
|
||||
"Import_Result_Info": "{imported} sur {total} recettes ont été importées",
|
||||
@@ -284,6 +291,7 @@
|
||||
"Last": "Dernier",
|
||||
"Last_name": "Nom",
|
||||
"Learn_More": "Apprenez-en plus",
|
||||
"LeaveSpace": "",
|
||||
"Link": "Lien",
|
||||
"Load": "Chargement",
|
||||
"Load_More": "Charger plus",
|
||||
@@ -358,6 +366,8 @@
|
||||
"Note": "Notes",
|
||||
"Number of Objects": "Nombre d'objets",
|
||||
"Nutrition": "Valeurs nutritionnelles",
|
||||
"NutritionsPerServing": "",
|
||||
"NutritionsPerServingHelp": "",
|
||||
"OfflineAlert": "Vous êtes déconnecté, votre liste de courses peut ne pas être synchronisée.",
|
||||
"Ok": "D'accord",
|
||||
"OnHand": "Disponible actuellement",
|
||||
@@ -494,17 +504,21 @@
|
||||
"Show_as_header": "Montrer comme en-tête",
|
||||
"Single": "Unique",
|
||||
"Size": "Taille",
|
||||
"Skip": "",
|
||||
"Social_Authentication": "Authentification Sociale",
|
||||
"Sort_by_new": "Trier par nouveautés",
|
||||
"Source": "Source",
|
||||
"SourceImportHelp": "Importez du JSON au format schema.org/recipe ou des pages HTML avec une recette json+ld ou des microdonnées.",
|
||||
"SourceImportSubtitle": "Importez en JSON ou HTML manuellement.",
|
||||
"Space": "",
|
||||
"SpaceHelp": "",
|
||||
"SpaceLimitExceeded": "Votre groupe a dépassé une de ses limites, certaines fonctions pourraient être restreintes.",
|
||||
"SpaceLimitReached": "Ce groupe a atteint sa limite. Aucun nouvel objet de ce type ne peut être créé.",
|
||||
"SpaceMemberHelp": "Ajoutez des utilisateurs à votre espace en créant un lien d'invitation et en l'envoyant à la personne que vous souhaitez ajouter.",
|
||||
"SpaceMembers": "Membres du groupe",
|
||||
"SpaceMembersHelp": "Utilisateurs et permissions dans un groupe. ",
|
||||
"SpaceMembersHelp": "",
|
||||
"SpaceName": "",
|
||||
"SpacePrivateObjectsHelp": "",
|
||||
"SpaceSettings": "Paramètres du groupe",
|
||||
"Space_Cosmetic_Settings": "Certains paramètres cosmétiques peuvent être modifiés par un administrateur de l'espace et seront prioritaires sur les paramètres des utilisateurs pour cet espace.",
|
||||
"Split": "Diviser",
|
||||
@@ -614,6 +628,8 @@
|
||||
"Week": "Semaine",
|
||||
"Week_Numbers": "Numéro de semaine",
|
||||
"Welcome": "Bienvenue",
|
||||
"WelcomeSettingsHelp": "",
|
||||
"WelcometoTandoor": "",
|
||||
"WorkingTime": "Temps de préparation",
|
||||
"Year": "Année",
|
||||
"Yes": "",
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
"API_Browser": "",
|
||||
"API_Documentation": "",
|
||||
"Account": "חשבון",
|
||||
"Active": "",
|
||||
"Add": "הוספה",
|
||||
"AddChild": "",
|
||||
"AddFoodToShopping": "הוסף {מזון} לרשימת הקניות",
|
||||
@@ -74,6 +75,8 @@
|
||||
"Create": "יצירה",
|
||||
"Create Food": "צור מאכל",
|
||||
"Create Recipe": "צור מתכון",
|
||||
"CreateFirstRecipe": "",
|
||||
"CreateInvitation": "",
|
||||
"Create_Meal_Plan_Entry": "צור רשימת תכנון אוכל",
|
||||
"Create_New_Food": "הוסף אוכל חדש",
|
||||
"Create_New_Keyword": "הוסף מילת מפתח",
|
||||
@@ -159,6 +162,7 @@
|
||||
"FuzzySearchHelp": "",
|
||||
"Global": "",
|
||||
"GlobalHelp": "",
|
||||
"Group": "",
|
||||
"GroupBy": "אסוף לפי",
|
||||
"Hide_Food": "הסתר אוכל",
|
||||
"Hide_Keyword": "הסתר מילות מפתח",
|
||||
@@ -177,6 +181,9 @@
|
||||
"Image": "תמונה",
|
||||
"Import": "ייבוא",
|
||||
"Import Recipe": "ייבא מתכון",
|
||||
"ImportFirstRecipe": "",
|
||||
"ImportMealPlans": "",
|
||||
"ImportShoppingList": "",
|
||||
"Import_Error": "שגיאה בעת ייבוא. הרחב את הפירוט בסוף עמוד זה לראות מידע נוסף.",
|
||||
"Import_Not_Yet_Supported": "ייבוא לא נתמך עדיין",
|
||||
"Import_Result_Info": "{imported} מתוך {total} מתכונים יובאו",
|
||||
@@ -207,6 +214,7 @@
|
||||
"Language": "שפה",
|
||||
"Last_name": "שם משפחה",
|
||||
"Learn_More": "למד עוד",
|
||||
"LeaveSpace": "",
|
||||
"Link": "קישור",
|
||||
"Load_More": "טען עוד",
|
||||
"LogCredits": "",
|
||||
@@ -268,6 +276,8 @@
|
||||
"Note": "הערה",
|
||||
"Number of Objects": "מספר אובייקטים",
|
||||
"Nutrition": "תזונה",
|
||||
"NutritionsPerServing": "",
|
||||
"NutritionsPerServingHelp": "",
|
||||
"OfflineAlert": "אתה במצב מנותק, רשימת הקניות לא בהכרח מסונכרנת.",
|
||||
"Ok": "אישור",
|
||||
"OnHand": "כרגע נגיש",
|
||||
@@ -361,9 +371,14 @@
|
||||
"Show_as_header": "הצג בתור כותרת",
|
||||
"Single": "בודד",
|
||||
"Size": "גודל",
|
||||
"Skip": "",
|
||||
"Social_Authentication": "אימות חברתי",
|
||||
"Sort_by_new": "סדר ע\"י חדש",
|
||||
"Space": "",
|
||||
"SpaceHelp": "",
|
||||
"SpaceMembersHelp": "",
|
||||
"SpaceName": "",
|
||||
"SpacePrivateObjectsHelp": "",
|
||||
"Space_Cosmetic_Settings": "חלק מהגדרות הקוסמטיות יכולות להיות מעודכנות על ידי מנהל המרחב וידרסו את הגדרות הקליינט עבור מרחב זה.",
|
||||
"Split_All_Steps": "פצל את כל השורות לצעדים נפרדים.",
|
||||
"StartDate": "תאריך התחלה",
|
||||
@@ -430,6 +445,8 @@
|
||||
"Week": "שבוע",
|
||||
"Week_Numbers": "מספר השבוע",
|
||||
"Welcome": "ברוכים הבאים",
|
||||
"WelcomeSettingsHelp": "",
|
||||
"WelcometoTandoor": "",
|
||||
"Year": "שנה",
|
||||
"Yes": "",
|
||||
"add_keyword": "הוסף מילת מפתח",
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
"API_Browser": "",
|
||||
"API_Documentation": "",
|
||||
"Account": "Korisnički račun",
|
||||
"Active": "",
|
||||
"Add": "Dodaj",
|
||||
"AddChild": "",
|
||||
"AddFoodToShopping": "Dodaj {food} na svoj popis za kupovinu",
|
||||
@@ -74,6 +75,8 @@
|
||||
"Create": "Stvori",
|
||||
"Create Food": "Kreiraj namirnicu",
|
||||
"Create Recipe": "Kreiraj recept",
|
||||
"CreateFirstRecipe": "",
|
||||
"CreateInvitation": "",
|
||||
"Create_Meal_Plan_Entry": "Kreirajte unos plana obroka",
|
||||
"Create_New_Food": "Dodaj novu namirnicu",
|
||||
"Create_New_Keyword": "Dodaj novu ključnu riječ",
|
||||
@@ -159,6 +162,7 @@
|
||||
"FuzzySearchHelp": "",
|
||||
"Global": "",
|
||||
"GlobalHelp": "",
|
||||
"Group": "",
|
||||
"GroupBy": "Grupiraj po",
|
||||
"Hide_Food": "Sakrij namirnicu",
|
||||
"Hide_Keyword": "Sakrij ključne riječi",
|
||||
@@ -177,6 +181,9 @@
|
||||
"Image": "Slika",
|
||||
"Import": "Uvoz",
|
||||
"Import Recipe": "Uvezi recept",
|
||||
"ImportFirstRecipe": "",
|
||||
"ImportMealPlans": "",
|
||||
"ImportShoppingList": "",
|
||||
"Import_Error": "Došlo je do pogreške tijekom uvoza. Molimo proširite pojedinosti na dnu stranice kako bi vidjeli grešku.",
|
||||
"Import_Not_Yet_Supported": "Uvoz još nije podržan",
|
||||
"Import_Result_Info": "Uvezeno je {imported} od {total} recepata",
|
||||
@@ -207,6 +214,7 @@
|
||||
"Language": "Jezik",
|
||||
"Last_name": "Prezime",
|
||||
"Learn_More": "Saznajte više",
|
||||
"LeaveSpace": "",
|
||||
"Link": "Poveznica",
|
||||
"Load_More": "Učitaj više",
|
||||
"LogCredits": "",
|
||||
@@ -268,6 +276,8 @@
|
||||
"Note": "Bilješka",
|
||||
"Number of Objects": "Broj objekata",
|
||||
"Nutrition": "Nutritivna vrijednost",
|
||||
"NutritionsPerServing": "",
|
||||
"NutritionsPerServingHelp": "",
|
||||
"OfflineAlert": "Nisi na mreži, popis za kupnju se možda neće sinkronizirati.",
|
||||
"Ok": "Ok",
|
||||
"OnHand": "Trenutno pri ruci",
|
||||
@@ -361,9 +371,14 @@
|
||||
"Show_as_header": "Prikaži kao zaglavlje",
|
||||
"Single": "Jedna",
|
||||
"Size": "Veličina",
|
||||
"Skip": "",
|
||||
"Social_Authentication": "Autentifikacija putem društvenih mreža",
|
||||
"Sort_by_new": "Poredaj po novom",
|
||||
"Space": "",
|
||||
"SpaceHelp": "",
|
||||
"SpaceMembersHelp": "",
|
||||
"SpaceName": "",
|
||||
"SpacePrivateObjectsHelp": "",
|
||||
"Space_Cosmetic_Settings": "Neke kozmetičke postavke mogu promijeniti administratori prostora i one će poništiti postavke klijenta za taj prostor.",
|
||||
"Split_All_Steps": "Podijeli sve retke u zasebne korake.",
|
||||
"StartDate": "Početni datum",
|
||||
@@ -430,6 +445,8 @@
|
||||
"Week": "Tjedan",
|
||||
"Week_Numbers": "Brojevi tjedana",
|
||||
"Welcome": "Dobrodošli",
|
||||
"WelcomeSettingsHelp": "",
|
||||
"WelcometoTandoor": "",
|
||||
"Year": "Godina",
|
||||
"Yes": "",
|
||||
"add_keyword": "Dodaj ključnu riječ",
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
"API_Browser": "",
|
||||
"API_Documentation": "",
|
||||
"Account": "Fiók",
|
||||
"Active": "",
|
||||
"Add": "Hozzáadás",
|
||||
"AddChild": "",
|
||||
"AddFoodToShopping": "{food} hozzáadása bevásárlólistához",
|
||||
@@ -72,6 +73,8 @@
|
||||
"Create": "Létrehozás",
|
||||
"Create Food": "Alapanyag létrehozása",
|
||||
"Create Recipe": "Recept létrehozása",
|
||||
"CreateFirstRecipe": "",
|
||||
"CreateInvitation": "",
|
||||
"Create_Meal_Plan_Entry": "Menüterv bejegyzés létrehozása",
|
||||
"Create_New_Food": "Új alapanyag hozzáadása",
|
||||
"Create_New_Keyword": "Új kulcsszó hozzáadása",
|
||||
@@ -142,6 +145,7 @@
|
||||
"FuzzySearchHelp": "",
|
||||
"Global": "",
|
||||
"GlobalHelp": "",
|
||||
"Group": "",
|
||||
"GroupBy": "Csoportosítva",
|
||||
"Hide_Food": "Alapanyag elrejtése",
|
||||
"Hide_Keyword": "Kulcsszavak elrejtése",
|
||||
@@ -160,6 +164,9 @@
|
||||
"Image": "Kép",
|
||||
"Import": "Import",
|
||||
"Import Recipe": "Recept importálása",
|
||||
"ImportFirstRecipe": "",
|
||||
"ImportMealPlans": "",
|
||||
"ImportShoppingList": "",
|
||||
"Import_Error": "Hiba történt az importálás során. Kérjük, a megtekintéshez bontsa ki az oldal alján található Részletek menüpontot.",
|
||||
"Import_Not_Yet_Supported": "",
|
||||
"Import_Result_Info": "{total}-ból/ből {imported} recept importálva",
|
||||
@@ -189,6 +196,7 @@
|
||||
"Language": "Nyelv",
|
||||
"Last_name": "Vezetéknév",
|
||||
"Learn_More": "Tudjon meg többet",
|
||||
"LeaveSpace": "",
|
||||
"Link": "Link",
|
||||
"Load_More": "Továbbiak betöltése",
|
||||
"LogCredits": "",
|
||||
@@ -245,6 +253,8 @@
|
||||
"Note": "Megjegyzés",
|
||||
"Number of Objects": "Objektumok száma",
|
||||
"Nutrition": "Tápérték",
|
||||
"NutritionsPerServing": "",
|
||||
"NutritionsPerServingHelp": "",
|
||||
"OfflineAlert": "Ön éppen offline állapotban van, a bevásárlólista nem biztos, hogy szinkronizálódik.",
|
||||
"Ok": "Ok",
|
||||
"OnHand": "Jelenleg készleten",
|
||||
@@ -329,8 +339,13 @@
|
||||
"Show_as_header": "Megjelenítés címként",
|
||||
"Single": "Egyetlen",
|
||||
"Size": "Méret",
|
||||
"Skip": "",
|
||||
"Sort_by_new": "Rendezés legújabbak szerint",
|
||||
"Space": "",
|
||||
"SpaceHelp": "",
|
||||
"SpaceMembersHelp": "",
|
||||
"SpaceName": "",
|
||||
"SpacePrivateObjectsHelp": "",
|
||||
"Split_All_Steps": "Ossza fel az összes sort különálló lépésekbe.",
|
||||
"StartDate": "Kezdés dátuma",
|
||||
"Starting_Day": "A hét kezdőnapja",
|
||||
@@ -390,6 +405,8 @@
|
||||
"Week": "Hét",
|
||||
"Week_Numbers": "",
|
||||
"Welcome": "Üdvözöljük",
|
||||
"WelcomeSettingsHelp": "",
|
||||
"WelcometoTandoor": "",
|
||||
"Year": "Év",
|
||||
"Yes": "",
|
||||
"add_keyword": "Kulcsszó hozzáadása",
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"AISettingsHostedHelp": "",
|
||||
"API_Browser": "",
|
||||
"API_Documentation": "",
|
||||
"Active": "",
|
||||
"Add": "",
|
||||
"AddChild": "",
|
||||
"Add_nutrition_recipe": "Ավելացնել սննդայնություն բաղադրատոմսին",
|
||||
@@ -32,6 +33,8 @@
|
||||
"ConvertUsingAI": "",
|
||||
"Copy": "",
|
||||
"Create": "Ստեղծել",
|
||||
"CreateFirstRecipe": "",
|
||||
"CreateInvitation": "",
|
||||
"Create_New_Food": "Ավելացնել նոր սննդամթերք",
|
||||
"Create_New_Keyword": "Ավելացնել նոր բանալի բառ",
|
||||
"Create_New_Shopping Category": "Ստեղծել գնումների նոր կատեգորիա",
|
||||
@@ -67,6 +70,7 @@
|
||||
"FuzzySearchHelp": "",
|
||||
"Global": "",
|
||||
"GlobalHelp": "",
|
||||
"Group": "",
|
||||
"Hide_Food": "Թաքցնել սննդամթերքը",
|
||||
"Hide_Keywords": "Թաքցնել բանալի բառը",
|
||||
"Hide_Recipes": "Թաքցնել բաղադրատոմսերը",
|
||||
@@ -75,10 +79,14 @@
|
||||
"IgnoreAccents": "",
|
||||
"IgnoreAccentsHelp": "",
|
||||
"Import": "Ներմուծել",
|
||||
"ImportFirstRecipe": "",
|
||||
"ImportMealPlans": "",
|
||||
"ImportShoppingList": "",
|
||||
"Import_finished": "Ներմուծումն ավարտված է",
|
||||
"Information": "Տեղեկություն",
|
||||
"Ingredients": "",
|
||||
"Keywords": "",
|
||||
"LeaveSpace": "",
|
||||
"Link": "",
|
||||
"Load_More": "",
|
||||
"LogCredits": "",
|
||||
@@ -106,6 +114,8 @@
|
||||
"NoUnit": "",
|
||||
"No_Results": "Արդյունքներ չկան",
|
||||
"Nutrition": "",
|
||||
"NutritionsPerServing": "",
|
||||
"NutritionsPerServingHelp": "",
|
||||
"Ok": "",
|
||||
"Open": "",
|
||||
"Parent": "Ծնող",
|
||||
@@ -146,8 +156,13 @@
|
||||
"Shopping_list": "Գնումների ցուցակ",
|
||||
"Show_as_header": "Ցույց տալ որպես խորագիր",
|
||||
"Size": "",
|
||||
"Skip": "",
|
||||
"Sort_by_new": "Տեսակավորել ըստ նորերի",
|
||||
"Space": "",
|
||||
"SpaceHelp": "",
|
||||
"SpaceMembersHelp": "",
|
||||
"SpaceName": "",
|
||||
"SpacePrivateObjectsHelp": "",
|
||||
"StartsWith": "",
|
||||
"StartsWithHelp": "",
|
||||
"Step": "",
|
||||
@@ -167,6 +182,8 @@
|
||||
"View_Recipes": "Դիտել բաղադրատոմսերը",
|
||||
"Visibility": "",
|
||||
"Waiting": "",
|
||||
"WelcomeSettingsHelp": "",
|
||||
"WelcometoTandoor": "",
|
||||
"Yes": "",
|
||||
"all_fields_optional": "Բոլոր տողերը կամավոր են և կարող են մնալ դատարկ։",
|
||||
"and": "և",
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
"API_Browser": "",
|
||||
"API_Documentation": "",
|
||||
"Account": "",
|
||||
"Active": "",
|
||||
"Add": "Tambahkan",
|
||||
"AddChild": "",
|
||||
"AddFoodToShopping": "",
|
||||
@@ -64,6 +65,8 @@
|
||||
"CountMore": "",
|
||||
"Create": "Membuat",
|
||||
"Create Food": "",
|
||||
"CreateFirstRecipe": "",
|
||||
"CreateInvitation": "",
|
||||
"Create_Meal_Plan_Entry": "",
|
||||
"Create_New_Food": "",
|
||||
"Create_New_Keyword": "",
|
||||
@@ -130,6 +133,7 @@
|
||||
"FuzzySearchHelp": "",
|
||||
"Global": "",
|
||||
"GlobalHelp": "",
|
||||
"Group": "",
|
||||
"GroupBy": "",
|
||||
"Hide_Food": "",
|
||||
"Hide_Keyword": "",
|
||||
@@ -147,6 +151,9 @@
|
||||
"IgnoredFood": "",
|
||||
"Image": "Gambar",
|
||||
"Import": "Impor",
|
||||
"ImportFirstRecipe": "",
|
||||
"ImportMealPlans": "",
|
||||
"ImportShoppingList": "",
|
||||
"Import_Error": "",
|
||||
"Import_Not_Yet_Supported": "",
|
||||
"Import_Result_Info": "",
|
||||
@@ -174,6 +181,7 @@
|
||||
"Keywords": "Kata Kunci",
|
||||
"Language": "",
|
||||
"Last_name": "",
|
||||
"LeaveSpace": "",
|
||||
"Link": "Link",
|
||||
"Load_More": "Muat lebih banyak",
|
||||
"LogCredits": "",
|
||||
@@ -228,6 +236,8 @@
|
||||
"NotInShopping": "",
|
||||
"Note": "Catatan",
|
||||
"Nutrition": "Nutrisi",
|
||||
"NutritionsPerServing": "",
|
||||
"NutritionsPerServingHelp": "",
|
||||
"OfflineAlert": "",
|
||||
"Ok": "Membuka",
|
||||
"OnHand": "",
|
||||
@@ -305,9 +315,14 @@
|
||||
"Show_as_header": "Tampilkan sebagai tajuk",
|
||||
"Single": "",
|
||||
"Size": "Ukuran",
|
||||
"Skip": "",
|
||||
"Social_Authentication": "",
|
||||
"Sort_by_new": "Urutkan berdasarkan baru",
|
||||
"Space": "",
|
||||
"SpaceHelp": "",
|
||||
"SpaceMembersHelp": "",
|
||||
"SpaceName": "",
|
||||
"SpacePrivateObjectsHelp": "",
|
||||
"Starting_Day": "",
|
||||
"StartsWith": "",
|
||||
"StartsWithHelp": "",
|
||||
@@ -357,6 +372,8 @@
|
||||
"Website": "",
|
||||
"Week": "",
|
||||
"Week_Numbers": "",
|
||||
"WelcomeSettingsHelp": "",
|
||||
"WelcometoTandoor": "",
|
||||
"Year": "",
|
||||
"Yes": "",
|
||||
"add_keyword": "",
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
"API_Browser": "",
|
||||
"API_Documentation": "",
|
||||
"Account": "",
|
||||
"Active": "",
|
||||
"Add": "",
|
||||
"AddChild": "",
|
||||
"AddFoodToShopping": "",
|
||||
@@ -74,6 +75,8 @@
|
||||
"Create": "",
|
||||
"Create Food": "",
|
||||
"Create Recipe": "",
|
||||
"CreateFirstRecipe": "",
|
||||
"CreateInvitation": "",
|
||||
"Create_Meal_Plan_Entry": "",
|
||||
"Create_New_Food": "",
|
||||
"Create_New_Keyword": "",
|
||||
@@ -158,6 +161,7 @@
|
||||
"FuzzySearchHelp": "",
|
||||
"Global": "",
|
||||
"GlobalHelp": "",
|
||||
"Group": "",
|
||||
"GroupBy": "",
|
||||
"Hide_Food": "",
|
||||
"Hide_Keyword": "",
|
||||
@@ -176,6 +180,9 @@
|
||||
"Image": "",
|
||||
"Import": "",
|
||||
"Import Recipe": "",
|
||||
"ImportFirstRecipe": "",
|
||||
"ImportMealPlans": "",
|
||||
"ImportShoppingList": "",
|
||||
"Import_Error": "",
|
||||
"Import_Not_Yet_Supported": "",
|
||||
"Import_Result_Info": "",
|
||||
@@ -206,6 +213,7 @@
|
||||
"Language": "",
|
||||
"Last_name": "",
|
||||
"Learn_More": "",
|
||||
"LeaveSpace": "",
|
||||
"Link": "",
|
||||
"Load_More": "",
|
||||
"LogCredits": "",
|
||||
@@ -267,6 +275,8 @@
|
||||
"Note": "",
|
||||
"Number of Objects": "",
|
||||
"Nutrition": "",
|
||||
"NutritionsPerServing": "",
|
||||
"NutritionsPerServingHelp": "",
|
||||
"OfflineAlert": "",
|
||||
"Ok": "",
|
||||
"OnHand": "",
|
||||
@@ -359,9 +369,14 @@
|
||||
"Show_as_header": "",
|
||||
"Single": "",
|
||||
"Size": "",
|
||||
"Skip": "",
|
||||
"Social_Authentication": "",
|
||||
"Sort_by_new": "",
|
||||
"Space": "",
|
||||
"SpaceHelp": "",
|
||||
"SpaceMembersHelp": "",
|
||||
"SpaceName": "",
|
||||
"SpacePrivateObjectsHelp": "",
|
||||
"Space_Cosmetic_Settings": "",
|
||||
"Split_All_Steps": "",
|
||||
"StartDate": "",
|
||||
@@ -428,6 +443,8 @@
|
||||
"Week": "",
|
||||
"Week_Numbers": "",
|
||||
"Welcome": "",
|
||||
"WelcomeSettingsHelp": "",
|
||||
"WelcometoTandoor": "",
|
||||
"Year": "",
|
||||
"Yes": "",
|
||||
"add_keyword": "",
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
"Access_Token": "Token di accesso",
|
||||
"Account": "Account",
|
||||
"Actions": "Azioni",
|
||||
"Active": "",
|
||||
"Activity": "Attività",
|
||||
"Add": "Aggiungi",
|
||||
"AddAll": "Aggiungi tutto",
|
||||
@@ -109,6 +110,8 @@
|
||||
"Create": "Crea",
|
||||
"Create Food": "Crea alimento",
|
||||
"Create Recipe": "Crea ricetta",
|
||||
"CreateFirstRecipe": "",
|
||||
"CreateInvitation": "",
|
||||
"Create_Meal_Plan_Entry": "Crea voce nel piano alimentare",
|
||||
"Create_New_Food": "Aggiungi nuovo alimento",
|
||||
"Create_New_Keyword": "Aggiungi nuova parola chiave",
|
||||
@@ -220,6 +223,7 @@
|
||||
"GettingStarted": "Iniziamo",
|
||||
"Global": "",
|
||||
"GlobalHelp": "",
|
||||
"Group": "",
|
||||
"GroupBy": "Raggruppa per",
|
||||
"HeaderWarning": "Attenzione: la modifica in un'intestazione elimina l'importo/unità/alimento",
|
||||
"Headline": "Intestazione",
|
||||
@@ -245,7 +249,10 @@
|
||||
"Import": "Importa",
|
||||
"Import Recipe": "Importa ricetta",
|
||||
"ImportAll": "Importa tutto",
|
||||
"ImportFirstRecipe": "",
|
||||
"ImportIntoTandoor": "Importa in Tandoor",
|
||||
"ImportMealPlans": "",
|
||||
"ImportShoppingList": "",
|
||||
"Import_Error": "Si è verificato un errore durante l'importazione. Per avere maggiori informazioni, espandi la sezione dettagli in fondo alla pagina.",
|
||||
"Import_Not_Yet_Supported": "Importazione non ancora supportata",
|
||||
"Import_Result_Info": "{imported} di {total} ricette sono state importate",
|
||||
@@ -284,6 +291,7 @@
|
||||
"Last": "Ultimo",
|
||||
"Last_name": "Cognome",
|
||||
"Learn_More": "Scopri altro",
|
||||
"LeaveSpace": "",
|
||||
"Link": "Collegamento",
|
||||
"Load": "Carica",
|
||||
"Load_More": "Carica altro",
|
||||
@@ -360,6 +368,8 @@
|
||||
"Note": "Nota",
|
||||
"Number of Objects": "Numero di oggetti",
|
||||
"Nutrition": "Nutrienti",
|
||||
"NutritionsPerServing": "",
|
||||
"NutritionsPerServingHelp": "",
|
||||
"OfflineAlert": "Sei offline, le liste della spesa potrebbero non sincronizzarsi.",
|
||||
"Ok": "Ok",
|
||||
"OnHand": "Attualmente disponibili",
|
||||
@@ -496,17 +506,21 @@
|
||||
"Show_as_header": "Mostra come intestazione",
|
||||
"Single": "Singolo",
|
||||
"Size": "Dimensione",
|
||||
"Skip": "",
|
||||
"Social_Authentication": "Autenticazione social",
|
||||
"Sort_by_new": "Prima i nuovi",
|
||||
"Source": "Fonte",
|
||||
"SourceImportHelp": "Importa JSON nel formato schema.org/recipe o pagine HTML con ricetta json+ld o microdati.",
|
||||
"SourceImportSubtitle": "Importa manualmente JSON o HTML.",
|
||||
"Space": "",
|
||||
"SpaceHelp": "",
|
||||
"SpaceLimitExceeded": "Il tuo spazio ha superato uno dei suoi limiti, alcune funzioni potrebbero essere limitate.",
|
||||
"SpaceLimitReached": "Questo spazio ha raggiunto il limite. Non è possibile creare altri oggetti di questo tipo.",
|
||||
"SpaceMemberHelp": "Aggiungi utenti al tuo spazio creando un collegamento di invito e inviandolo alla persona che desideri aggiungere.",
|
||||
"SpaceMembers": "Membri dello spazio",
|
||||
"SpaceMembersHelp": "Utenti e relativi permessi in uno spazio. ",
|
||||
"SpaceMembersHelp": "",
|
||||
"SpaceName": "",
|
||||
"SpacePrivateObjectsHelp": "",
|
||||
"SpaceSettings": "Impostazioni spazio",
|
||||
"Space_Cosmetic_Settings": "Alcune impostazioni cosmetiche possono essere modificate dagli amministratori dell'istanza e sovrascriveranno le impostazioni client per quell'istanza.",
|
||||
"Split": "Dividi",
|
||||
@@ -616,6 +630,8 @@
|
||||
"Week": "Settimana",
|
||||
"Week_Numbers": "Numeri della settimana",
|
||||
"Welcome": "Benvenuto",
|
||||
"WelcomeSettingsHelp": "",
|
||||
"WelcometoTandoor": "",
|
||||
"WorkingTime": "Orario lavorativo",
|
||||
"Year": "Anno",
|
||||
"Yes": "",
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
"API_Browser": "",
|
||||
"API_Documentation": "",
|
||||
"Account": "",
|
||||
"Active": "",
|
||||
"Add": "",
|
||||
"AddChild": "",
|
||||
"AddFoodToShopping": "",
|
||||
@@ -73,6 +74,8 @@
|
||||
"Create": "",
|
||||
"Create Food": "",
|
||||
"Create Recipe": "",
|
||||
"CreateFirstRecipe": "",
|
||||
"CreateInvitation": "",
|
||||
"Create_Meal_Plan_Entry": "",
|
||||
"Create_New_Food": "",
|
||||
"Create_New_Keyword": "",
|
||||
@@ -144,6 +147,7 @@
|
||||
"FuzzySearchHelp": "",
|
||||
"Global": "",
|
||||
"GlobalHelp": "",
|
||||
"Group": "",
|
||||
"GroupBy": "",
|
||||
"Hide_Food": "",
|
||||
"Hide_Keyword": "",
|
||||
@@ -162,6 +166,9 @@
|
||||
"Image": "",
|
||||
"Import": "",
|
||||
"Import Recipe": "",
|
||||
"ImportFirstRecipe": "",
|
||||
"ImportMealPlans": "",
|
||||
"ImportShoppingList": "",
|
||||
"Import_Error": "",
|
||||
"Import_Not_Yet_Supported": "",
|
||||
"Import_Result_Info": "",
|
||||
@@ -191,6 +198,7 @@
|
||||
"Language": "",
|
||||
"Last_name": "",
|
||||
"Learn_More": "",
|
||||
"LeaveSpace": "",
|
||||
"Link": "",
|
||||
"Load_More": "Įkelti daugiau",
|
||||
"LogCredits": "",
|
||||
@@ -248,6 +256,8 @@
|
||||
"Note": "",
|
||||
"Number of Objects": "",
|
||||
"Nutrition": "",
|
||||
"NutritionsPerServing": "",
|
||||
"NutritionsPerServingHelp": "",
|
||||
"OfflineAlert": "",
|
||||
"Ok": "",
|
||||
"OnHand": "",
|
||||
@@ -333,9 +343,14 @@
|
||||
"Show_as_header": "Rodyti kaip antraštę",
|
||||
"Single": "",
|
||||
"Size": "",
|
||||
"Skip": "",
|
||||
"Social_Authentication": "",
|
||||
"Sort_by_new": "Rūšiuoti pagal naujumą",
|
||||
"Space": "",
|
||||
"SpaceHelp": "",
|
||||
"SpaceMembersHelp": "",
|
||||
"SpaceName": "",
|
||||
"SpacePrivateObjectsHelp": "",
|
||||
"Split_All_Steps": "",
|
||||
"StartDate": "",
|
||||
"Starting_Day": "",
|
||||
@@ -398,6 +413,8 @@
|
||||
"Week": "",
|
||||
"Week_Numbers": "",
|
||||
"Welcome": "",
|
||||
"WelcomeSettingsHelp": "",
|
||||
"WelcometoTandoor": "",
|
||||
"Year": "",
|
||||
"Yes": "",
|
||||
"add_keyword": "",
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
"API_Browser": "",
|
||||
"API_Documentation": "",
|
||||
"Account": "",
|
||||
"Active": "",
|
||||
"Add": "",
|
||||
"AddChild": "",
|
||||
"AddFoodToShopping": "",
|
||||
@@ -74,6 +75,8 @@
|
||||
"Create": "",
|
||||
"Create Food": "",
|
||||
"Create Recipe": "",
|
||||
"CreateFirstRecipe": "",
|
||||
"CreateInvitation": "",
|
||||
"Create_Meal_Plan_Entry": "",
|
||||
"Create_New_Food": "",
|
||||
"Create_New_Keyword": "",
|
||||
@@ -159,6 +162,7 @@
|
||||
"FuzzySearchHelp": "",
|
||||
"Global": "",
|
||||
"GlobalHelp": "",
|
||||
"Group": "",
|
||||
"GroupBy": "",
|
||||
"Hide_Food": "",
|
||||
"Hide_Keyword": "",
|
||||
@@ -177,6 +181,9 @@
|
||||
"Image": "",
|
||||
"Import": "",
|
||||
"Import Recipe": "",
|
||||
"ImportFirstRecipe": "",
|
||||
"ImportMealPlans": "",
|
||||
"ImportShoppingList": "",
|
||||
"Import_Error": "",
|
||||
"Import_Not_Yet_Supported": "",
|
||||
"Import_Result_Info": "",
|
||||
@@ -207,6 +214,7 @@
|
||||
"Language": "",
|
||||
"Last_name": "",
|
||||
"Learn_More": "",
|
||||
"LeaveSpace": "",
|
||||
"Link": "",
|
||||
"Load_More": "",
|
||||
"LogCredits": "",
|
||||
@@ -268,6 +276,8 @@
|
||||
"Note": "",
|
||||
"Number of Objects": "",
|
||||
"Nutrition": "",
|
||||
"NutritionsPerServing": "",
|
||||
"NutritionsPerServingHelp": "",
|
||||
"OfflineAlert": "",
|
||||
"Ok": "",
|
||||
"OnHand": "",
|
||||
@@ -361,9 +371,14 @@
|
||||
"Show_as_header": "",
|
||||
"Single": "",
|
||||
"Size": "",
|
||||
"Skip": "",
|
||||
"Social_Authentication": "",
|
||||
"Sort_by_new": "",
|
||||
"Space": "",
|
||||
"SpaceHelp": "",
|
||||
"SpaceMembersHelp": "",
|
||||
"SpaceName": "",
|
||||
"SpacePrivateObjectsHelp": "",
|
||||
"Space_Cosmetic_Settings": "",
|
||||
"Split_All_Steps": "",
|
||||
"StartDate": "",
|
||||
@@ -430,6 +445,8 @@
|
||||
"Week": "",
|
||||
"Week_Numbers": "",
|
||||
"Welcome": "",
|
||||
"WelcomeSettingsHelp": "",
|
||||
"WelcometoTandoor": "",
|
||||
"Year": "",
|
||||
"Yes": "",
|
||||
"add_keyword": "",
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
"API_Browser": "",
|
||||
"API_Documentation": "",
|
||||
"Account": "",
|
||||
"Active": "",
|
||||
"Add": "Legg til",
|
||||
"AddChild": "",
|
||||
"AddFoodToShopping": "Legg til {food] i handlelisten din",
|
||||
@@ -72,6 +73,8 @@
|
||||
"Create": "Opprett",
|
||||
"Create Food": "",
|
||||
"Create Recipe": "",
|
||||
"CreateFirstRecipe": "",
|
||||
"CreateInvitation": "",
|
||||
"Create_Meal_Plan_Entry": "Opprett måltidsplanoppføring",
|
||||
"Create_New_Food": "Opprett ny matrett",
|
||||
"Create_New_Keyword": "Opprett nytt nøkkelord",
|
||||
@@ -150,6 +153,7 @@
|
||||
"FuzzySearchHelp": "",
|
||||
"Global": "",
|
||||
"GlobalHelp": "",
|
||||
"Group": "",
|
||||
"GroupBy": "Grupér",
|
||||
"Hide_Food": "Skjul Matrett",
|
||||
"Hide_Keyword": "Skjul nøkkelord",
|
||||
@@ -168,6 +172,9 @@
|
||||
"Image": "Bilde",
|
||||
"Import": "Importer",
|
||||
"Import Recipe": "Importer oppskrift",
|
||||
"ImportFirstRecipe": "",
|
||||
"ImportMealPlans": "",
|
||||
"ImportShoppingList": "",
|
||||
"Import_Error": "",
|
||||
"Import_Not_Yet_Supported": "",
|
||||
"Import_Result_Info": "",
|
||||
@@ -198,6 +205,7 @@
|
||||
"Language": "Språk",
|
||||
"Last_name": "Etternavn",
|
||||
"Learn_More": "Lær mer",
|
||||
"LeaveSpace": "",
|
||||
"Link": "Lenke",
|
||||
"Load_More": "Last inn flere",
|
||||
"LogCredits": "",
|
||||
@@ -254,6 +262,8 @@
|
||||
"Note": "Merk",
|
||||
"Number of Objects": "Antall objekter",
|
||||
"Nutrition": "Næringsinnhold",
|
||||
"NutritionsPerServing": "",
|
||||
"NutritionsPerServingHelp": "",
|
||||
"OfflineAlert": "Du er ikke koblet til internett. Det kan hende handlelisten ikke synkroniserer.",
|
||||
"Ok": "Ok",
|
||||
"OnHand": "På lager",
|
||||
@@ -343,9 +353,14 @@
|
||||
"Show_as_header": "Vis som overskrift",
|
||||
"Single": "",
|
||||
"Size": "Størrelse",
|
||||
"Skip": "",
|
||||
"Social_Authentication": "",
|
||||
"Sort_by_new": "Sorter etter nyest",
|
||||
"Space": "",
|
||||
"SpaceHelp": "",
|
||||
"SpaceMembersHelp": "",
|
||||
"SpaceName": "",
|
||||
"SpacePrivateObjectsHelp": "",
|
||||
"Split_All_Steps": "",
|
||||
"StartDate": "Startdato",
|
||||
"Starting_Day": "Dag uken skal state på",
|
||||
@@ -407,6 +422,8 @@
|
||||
"Week": "Uke",
|
||||
"Week_Numbers": "Ukenummer",
|
||||
"Welcome": "Velkommen",
|
||||
"WelcomeSettingsHelp": "",
|
||||
"WelcometoTandoor": "",
|
||||
"Year": "År",
|
||||
"Yes": "",
|
||||
"add_keyword": "",
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
"Access_Token": "Toegangstoken",
|
||||
"Account": "Account",
|
||||
"Actions": "Acties",
|
||||
"Active": "",
|
||||
"Activity": "Activiteit",
|
||||
"Add": "Voeg toe",
|
||||
"AddAll": "Voeg alles toe",
|
||||
@@ -110,6 +111,8 @@
|
||||
"Create": "Aanmaken",
|
||||
"Create Food": "Maak voedingsmiddel",
|
||||
"Create Recipe": "Maak recept",
|
||||
"CreateFirstRecipe": "",
|
||||
"CreateInvitation": "",
|
||||
"Create_Meal_Plan_Entry": "Maak maaltijdplan",
|
||||
"Create_New_Food": "Voeg nieuw voedingsmiddel toe",
|
||||
"Create_New_Keyword": "Voeg nieuw trefwoord toe",
|
||||
@@ -221,6 +224,7 @@
|
||||
"GettingStarted": "Aan de slag",
|
||||
"Global": "",
|
||||
"GlobalHelp": "",
|
||||
"Group": "",
|
||||
"GroupBy": "Groepeer per",
|
||||
"HeaderWarning": "Waarschuwing: Het wijzigen naar een kop verwijdert de hoeveelheid/eenheid/voedingsmiddel",
|
||||
"Headline": "Koptekst",
|
||||
@@ -246,7 +250,10 @@
|
||||
"Import": "Importeer",
|
||||
"Import Recipe": "Recept importeren",
|
||||
"ImportAll": "Alles importeren",
|
||||
"ImportFirstRecipe": "",
|
||||
"ImportIntoTandoor": "Importeer in Tandoor",
|
||||
"ImportMealPlans": "",
|
||||
"ImportShoppingList": "",
|
||||
"Import_Error": "Er is een fout opgetreden tijdens je import. Breid de details aan de onderzijde van de pagina uit om ze te bekijken.",
|
||||
"Import_Not_Yet_Supported": "Import nog niet ondersteund",
|
||||
"Import_Result_Info": "{imported} van {total} recepten zijn geïmporteerd",
|
||||
@@ -285,6 +292,7 @@
|
||||
"Last": "Laatste",
|
||||
"Last_name": "Achternaam",
|
||||
"Learn_More": "Meer informatie",
|
||||
"LeaveSpace": "",
|
||||
"Link": "Link",
|
||||
"Load": "Laden",
|
||||
"Load_More": "Laad meer",
|
||||
@@ -361,6 +369,8 @@
|
||||
"Note": "Notitie",
|
||||
"Number of Objects": "Aantal objecten",
|
||||
"Nutrition": "Voedingswaarde",
|
||||
"NutritionsPerServing": "",
|
||||
"NutritionsPerServingHelp": "",
|
||||
"OfflineAlert": "Je bent offline, boodschappenlijst synchroniseert mogelijk niet.",
|
||||
"Ok": "Ok",
|
||||
"OnHand": "Momenteel op voorraad",
|
||||
@@ -497,17 +507,21 @@
|
||||
"Show_as_header": "Toon als koptekst",
|
||||
"Single": "Enkele",
|
||||
"Size": "Grootte",
|
||||
"Skip": "",
|
||||
"Social_Authentication": "Authenticeren met sociale media-account",
|
||||
"Sort_by_new": "Sorteer op nieuw",
|
||||
"Source": "Bron",
|
||||
"SourceImportHelp": "Importeer JSON in schema.org/recipe-formaat of html-pagina’s met json+ld-recepten of microdata.",
|
||||
"SourceImportSubtitle": "Importeer handmatig JSON of HTML.",
|
||||
"Space": "",
|
||||
"SpaceHelp": "",
|
||||
"SpaceLimitExceeded": "Je ruimte heeft een limiet overschreden, sommige functies zijn mogelijk beperkt.",
|
||||
"SpaceLimitReached": "Deze ruimte heeft een limiet bereikt. Er kunnen geen objecten van dit type meer worden aangemaakt.",
|
||||
"SpaceMemberHelp": "Voeg gebruikers toe aan je ruimte door een uitnodigingslink aan te maken en naar de persoon te sturen die je wilt toevoegen.",
|
||||
"SpaceMembers": "Gebruikers van de ruimte",
|
||||
"SpaceMembersHelp": "Gebruikers en hun rechten in een ruimte. ",
|
||||
"SpaceMembersHelp": "",
|
||||
"SpaceName": "",
|
||||
"SpacePrivateObjectsHelp": "",
|
||||
"SpaceSettings": "Ruimte-instellingen",
|
||||
"Space_Cosmetic_Settings": "Sommige weergave instellingen kunnen worden geforceerd door de administrator van de 'Ruimte' en zullen de persoonlijke instellingen voor die 'Ruimte' overschrijven.",
|
||||
"Split": "Splitsen",
|
||||
@@ -617,6 +631,8 @@
|
||||
"Week": "Week",
|
||||
"Week_Numbers": "Weeknummers",
|
||||
"Welcome": "Welkom",
|
||||
"WelcomeSettingsHelp": "",
|
||||
"WelcometoTandoor": "",
|
||||
"WorkingTime": "Bereidingstijd",
|
||||
"Year": "Jaar",
|
||||
"Yes": "",
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
"Access_Token": "Token Dostępu",
|
||||
"Account": "Konto",
|
||||
"Actions": "Akcje",
|
||||
"Active": "",
|
||||
"Activity": "Aktywność",
|
||||
"Add": "Dodaj",
|
||||
"AddAll": "Dodaj wszystkie",
|
||||
@@ -100,6 +101,8 @@
|
||||
"Create": "Stwórz",
|
||||
"Create Food": "Twórz jedzenie",
|
||||
"Create Recipe": "Utwórz przepis",
|
||||
"CreateFirstRecipe": "",
|
||||
"CreateInvitation": "",
|
||||
"Create_Meal_Plan_Entry": "Utwórz wpis planu posiłków",
|
||||
"Create_New_Food": "Dodaj nową żywność",
|
||||
"Create_New_Keyword": "Dodaj nowe słowo kluczowe",
|
||||
@@ -185,6 +188,7 @@
|
||||
"FuzzySearchHelp": "",
|
||||
"Global": "",
|
||||
"GlobalHelp": "",
|
||||
"Group": "",
|
||||
"GroupBy": "Grupuj według",
|
||||
"Hide_Food": "Ukryj żywność",
|
||||
"Hide_Keyword": "Ukryj słowa kluczowe",
|
||||
@@ -203,6 +207,9 @@
|
||||
"Image": "Obraz",
|
||||
"Import": "Importuj",
|
||||
"Import Recipe": "Importuj przepis",
|
||||
"ImportFirstRecipe": "",
|
||||
"ImportMealPlans": "",
|
||||
"ImportShoppingList": "",
|
||||
"Import_Error": "Podczas importowania wystąpił błąd. Rozwiń Szczegóły na dole strony, aby go wyświetlić.",
|
||||
"Import_Not_Yet_Supported": "Importowanie jeszcze nie wspierane",
|
||||
"Import_Result_Info": "{imported} z {total} przepisów zostało zaimportowanych",
|
||||
@@ -233,6 +240,7 @@
|
||||
"Language": "Język",
|
||||
"Last_name": "Nazwisko",
|
||||
"Learn_More": "Dowiedz się więcej",
|
||||
"LeaveSpace": "",
|
||||
"Link": "Link",
|
||||
"Load_More": "Załaduj więcej",
|
||||
"LogCredits": "",
|
||||
@@ -294,6 +302,8 @@
|
||||
"Note": "Notatka",
|
||||
"Number of Objects": "Ilość obiektów",
|
||||
"Nutrition": "Odżywianie",
|
||||
"NutritionsPerServing": "",
|
||||
"NutritionsPerServingHelp": "",
|
||||
"OfflineAlert": "Jesteś offline, lista zakupów może nie być zsynchronizowana.",
|
||||
"Ok": "Ok",
|
||||
"OnHand": "Obecnie posiadane",
|
||||
@@ -387,9 +397,14 @@
|
||||
"Show_as_header": "Pokaż jako nagłówek",
|
||||
"Single": "Pojedynczy",
|
||||
"Size": "Rozmiar",
|
||||
"Skip": "",
|
||||
"Social_Authentication": "Uwierzytelnianie społecznościowe",
|
||||
"Sort_by_new": "Sortuj według nowych",
|
||||
"Space": "",
|
||||
"SpaceHelp": "",
|
||||
"SpaceMembersHelp": "",
|
||||
"SpaceName": "",
|
||||
"SpacePrivateObjectsHelp": "",
|
||||
"Space_Cosmetic_Settings": "Administratorzy przestrzeni mogą zmienić niektóre ustawienia kosmetyczne, które zastąpią ustawienia klienta dla tej przestrzeni.",
|
||||
"Split_All_Steps": "Traktuj każdy wiersz jako osobne kroki.",
|
||||
"StartDate": "Data początkowa",
|
||||
@@ -456,6 +471,8 @@
|
||||
"Week": "Tydzień",
|
||||
"Week_Numbers": "Numery tygodni",
|
||||
"Welcome": "Witamy",
|
||||
"WelcomeSettingsHelp": "",
|
||||
"WelcometoTandoor": "",
|
||||
"Year": "Rok",
|
||||
"Yes": "",
|
||||
"add_keyword": "Dodaj słowo kluczowe",
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"AISettingsHostedHelp": "",
|
||||
"API_Browser": "",
|
||||
"API_Documentation": "",
|
||||
"Active": "",
|
||||
"Add": "Adicionar",
|
||||
"AddChild": "",
|
||||
"AddFoodToShopping": "Adicionar {food} à sua lista de compras",
|
||||
@@ -61,6 +62,8 @@
|
||||
"CountMore": "...+{count} mais",
|
||||
"Create": "Criar",
|
||||
"Create Food": "Criar Comida",
|
||||
"CreateFirstRecipe": "",
|
||||
"CreateInvitation": "",
|
||||
"Create_Meal_Plan_Entry": "Criar entrada para plano de refeições",
|
||||
"Create_New_Food": "Adicionar nova comida",
|
||||
"Create_New_Keyword": "Adicionar nova palavra-chave",
|
||||
@@ -130,6 +133,7 @@
|
||||
"FuzzySearchHelp": "",
|
||||
"Global": "",
|
||||
"GlobalHelp": "",
|
||||
"Group": "",
|
||||
"GroupBy": "Agrupar por",
|
||||
"Hide_Food": "Esconder comida",
|
||||
"Hide_Keyword": "",
|
||||
@@ -145,6 +149,9 @@
|
||||
"IgnoredFood": "{food} está definida para ignorar compras.",
|
||||
"Image": "Image",
|
||||
"Import": "Importar",
|
||||
"ImportFirstRecipe": "",
|
||||
"ImportMealPlans": "",
|
||||
"ImportShoppingList": "",
|
||||
"Import_finished": "Importação terminada",
|
||||
"Information": "Informação",
|
||||
"Ingredient Editor": "Editor de Ingredientes",
|
||||
@@ -165,6 +172,7 @@
|
||||
"Keywords": "Palavras-chave",
|
||||
"Language": "Linguagem",
|
||||
"Learn_More": "Aprenda mais",
|
||||
"LeaveSpace": "",
|
||||
"Link": "Ligação",
|
||||
"Load_More": "Carregar Mais",
|
||||
"LogCredits": "",
|
||||
@@ -214,6 +222,8 @@
|
||||
"Note": "Nota",
|
||||
"Number of Objects": "Número de objetos",
|
||||
"Nutrition": "Nutrição",
|
||||
"NutritionsPerServing": "",
|
||||
"NutritionsPerServingHelp": "",
|
||||
"OfflineAlert": "Está offline, lista das compras poderá não sincronizar.",
|
||||
"Ok": "Ok",
|
||||
"OnHand": "Atualmente disponível",
|
||||
@@ -295,8 +305,13 @@
|
||||
"Show_Week_Numbers": "Mostrar números das semanas?",
|
||||
"Show_as_header": "Mostrar como cabeçalho",
|
||||
"Size": "Tamanho",
|
||||
"Skip": "",
|
||||
"Sort_by_new": "Ordenar por mais recente",
|
||||
"Space": "",
|
||||
"SpaceHelp": "",
|
||||
"SpaceMembersHelp": "",
|
||||
"SpaceName": "",
|
||||
"SpacePrivateObjectsHelp": "",
|
||||
"StartDate": "Data de início",
|
||||
"Starting_Day": "Dia de início da semana",
|
||||
"StartsWith": "",
|
||||
@@ -346,6 +361,8 @@
|
||||
"Week": "Semana",
|
||||
"Week_Numbers": "Números das semanas",
|
||||
"Welcome": "Bem-vindo",
|
||||
"WelcomeSettingsHelp": "",
|
||||
"WelcometoTandoor": "",
|
||||
"Year": "Ano",
|
||||
"Yes": "",
|
||||
"add_keyword": "Adicionar Palavra Chave",
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
"Access_Token": "Token de acesso",
|
||||
"Account": "Conta",
|
||||
"Actions": "Ações",
|
||||
"Active": "",
|
||||
"Activity": "Atividade",
|
||||
"Add": "Adicionar",
|
||||
"AddAll": "Adicionar todos",
|
||||
@@ -108,6 +109,8 @@
|
||||
"Create": "Criar",
|
||||
"Create Food": "Criar Alimento",
|
||||
"Create Recipe": "Criar Receita",
|
||||
"CreateFirstRecipe": "",
|
||||
"CreateInvitation": "",
|
||||
"Create_Meal_Plan_Entry": "Criar Plano de Refeição",
|
||||
"Create_New_Food": "Incluir Novo Alimento",
|
||||
"Create_New_Keyword": "Incluir Nova Palavra-Chave",
|
||||
@@ -219,6 +222,7 @@
|
||||
"GettingStarted": "Começando",
|
||||
"Global": "",
|
||||
"GlobalHelp": "",
|
||||
"Group": "",
|
||||
"GroupBy": "Agrupar Por",
|
||||
"HeaderWarning": "Alerta: Mudanças de Cabeçalho apagam a Quantidade/Unidade/Alimento",
|
||||
"Headline": "Título",
|
||||
@@ -244,7 +248,10 @@
|
||||
"Import": "Importar",
|
||||
"Import Recipe": "Importar Receita",
|
||||
"ImportAll": "Importar todos",
|
||||
"ImportFirstRecipe": "",
|
||||
"ImportIntoTandoor": "Importar para Tandoor",
|
||||
"ImportMealPlans": "",
|
||||
"ImportShoppingList": "",
|
||||
"Import_Error": "Ocorreu um erro durante a importação. Expanda os detalhes na parte inferior da página para visualizá-los.",
|
||||
"Import_Not_Yet_Supported": "Importação ainda não suportada",
|
||||
"Import_Result_Info": "{imported} de {total} receitas foram importadas",
|
||||
@@ -283,6 +290,7 @@
|
||||
"Last": "Último",
|
||||
"Last_name": "Último Nome",
|
||||
"Learn_More": "Aprender Mais",
|
||||
"LeaveSpace": "",
|
||||
"Link": "Link",
|
||||
"Load": "Carregar",
|
||||
"Load_More": "Carregar mais",
|
||||
@@ -348,6 +356,8 @@
|
||||
"Note": "Nota",
|
||||
"Number of Objects": "Número de Objetos",
|
||||
"Nutrition": "Nutrição",
|
||||
"NutritionsPerServing": "",
|
||||
"NutritionsPerServingHelp": "",
|
||||
"OfflineAlert": "Você está offline, a lista de compras não pode ser sincronizada.",
|
||||
"Ok": "Ok",
|
||||
"OnHand": "Atualmente disponível",
|
||||
@@ -435,9 +445,14 @@
|
||||
"Show_as_header": "Mostrar como título",
|
||||
"Single": "Simples",
|
||||
"Size": "Tamanho",
|
||||
"Skip": "",
|
||||
"Social_Authentication": "Autenticação social",
|
||||
"Sort_by_new": "Ordenar por novos",
|
||||
"Space": "",
|
||||
"SpaceHelp": "",
|
||||
"SpaceMembersHelp": "",
|
||||
"SpaceName": "",
|
||||
"SpacePrivateObjectsHelp": "",
|
||||
"Space_Cosmetic_Settings": "Algumas configurações cosméticas podem ser alteradas pelos administradores do espaço e substituirão as configurações do cliente para esse espaço.",
|
||||
"Split_All_Steps": "Divida todas as linhas em etapas separadas.",
|
||||
"StartDate": "Data Início",
|
||||
@@ -500,6 +515,8 @@
|
||||
"Week": "Semana",
|
||||
"Week_Numbers": "Números da Semana",
|
||||
"Welcome": "Bem vindo",
|
||||
"WelcomeSettingsHelp": "",
|
||||
"WelcometoTandoor": "",
|
||||
"Year": "Ano",
|
||||
"Yes": "",
|
||||
"add_keyword": "Incluir Palavra-Chave",
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
"API_Browser": "",
|
||||
"API_Documentation": "",
|
||||
"Account": "Cont",
|
||||
"Active": "",
|
||||
"Add": "Adaugă",
|
||||
"AddChild": "",
|
||||
"AddFoodToShopping": "Adăugă {food} în lista de cumpărături",
|
||||
@@ -70,6 +71,8 @@
|
||||
"Create": "Creează",
|
||||
"Create Food": "Creare mâncare",
|
||||
"Create Recipe": "Crearea rețetei",
|
||||
"CreateFirstRecipe": "",
|
||||
"CreateInvitation": "",
|
||||
"Create_Meal_Plan_Entry": "Crearea înregistrării în planul de alimentare",
|
||||
"Create_New_Food": "Adaugă mâncare nouă",
|
||||
"Create_New_Keyword": "Adaugă cuvânt cheie nou",
|
||||
@@ -137,6 +140,7 @@
|
||||
"FuzzySearchHelp": "",
|
||||
"Global": "",
|
||||
"GlobalHelp": "",
|
||||
"Group": "",
|
||||
"GroupBy": "Grupat de",
|
||||
"Hide_Food": "Ascunde mâncare",
|
||||
"Hide_Keyword": "Ascunde cuvintele cheie",
|
||||
@@ -155,6 +159,9 @@
|
||||
"Image": "Imagine",
|
||||
"Import": "Importă",
|
||||
"Import Recipe": "Importă rețeta",
|
||||
"ImportFirstRecipe": "",
|
||||
"ImportMealPlans": "",
|
||||
"ImportShoppingList": "",
|
||||
"Import_Error": "A apărut o eroare în timpul importului. Vă rugăm să extindeți detaliile din partea de jos a paginii pentru a le vizualiza.",
|
||||
"Import_Not_Yet_Supported": "Importul încă nu este compatibil",
|
||||
"Import_Result_Info": "{imported} din {total} rețete au fost importate",
|
||||
@@ -183,6 +190,7 @@
|
||||
"Keywords": "Cuvinte cheie",
|
||||
"Language": "Limba",
|
||||
"Last_name": "Nume de familie",
|
||||
"LeaveSpace": "",
|
||||
"Link": "Link",
|
||||
"Load_More": "Încărcați mai mult",
|
||||
"LogCredits": "",
|
||||
@@ -237,6 +245,8 @@
|
||||
"NotInShopping": "{food} nu se află în lista de cumpărături.",
|
||||
"Note": "Notă",
|
||||
"Nutrition": "Nutriție",
|
||||
"NutritionsPerServing": "",
|
||||
"NutritionsPerServingHelp": "",
|
||||
"OfflineAlert": "Sunteți offline, este posibil ca lista de cumpărături să nu se sincronizeze.",
|
||||
"Ok": "Ok",
|
||||
"OnHand": "În prezent, la îndemână",
|
||||
@@ -317,9 +327,14 @@
|
||||
"Show_as_header": "Afișare ca antet",
|
||||
"Single": "Singur",
|
||||
"Size": "Marime",
|
||||
"Skip": "",
|
||||
"Social_Authentication": "Autentificare socială",
|
||||
"Sort_by_new": "Sortare după nou",
|
||||
"Space": "",
|
||||
"SpaceHelp": "",
|
||||
"SpaceMembersHelp": "",
|
||||
"SpaceName": "",
|
||||
"SpacePrivateObjectsHelp": "",
|
||||
"Split_All_Steps": "Împărțiți toate rândurile în pași separați.",
|
||||
"Starting_Day": "Ziua de început a săptămânii",
|
||||
"StartsWith": "",
|
||||
@@ -376,6 +391,8 @@
|
||||
"Website": "Site web",
|
||||
"Week": "Săptămână",
|
||||
"Week_Numbers": "Numerele săptămânii",
|
||||
"WelcomeSettingsHelp": "",
|
||||
"WelcometoTandoor": "",
|
||||
"Year": "An",
|
||||
"Yes": "",
|
||||
"add_keyword": "Adăugare cuvânt cheie",
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
"Access_Token": "Токен доступа",
|
||||
"Account": "Аккаунт",
|
||||
"Actions": "Действия",
|
||||
"Active": "",
|
||||
"Activity": "Активность",
|
||||
"Add": "Добавить",
|
||||
"AddAll": "Добавить все",
|
||||
@@ -109,6 +110,8 @@
|
||||
"Create": "Создать",
|
||||
"Create Food": "Создать продукт",
|
||||
"Create Recipe": "Создать рецепт",
|
||||
"CreateFirstRecipe": "",
|
||||
"CreateInvitation": "",
|
||||
"Create_Meal_Plan_Entry": "Создать плана питания",
|
||||
"Create_New_Food": "Добавить новую еду",
|
||||
"Create_New_Keyword": "Добавить ключевое слово",
|
||||
@@ -220,6 +223,7 @@
|
||||
"GettingStarted": "Начало работы",
|
||||
"Global": "",
|
||||
"GlobalHelp": "",
|
||||
"Group": "",
|
||||
"GroupBy": "Сгруппировать по",
|
||||
"HeaderWarning": "Внимание: при преобразовании в заголовок удаляются данные о количестве, единице/измерения/продукте.",
|
||||
"Headline": "Заголовок",
|
||||
@@ -245,7 +249,10 @@
|
||||
"Import": "Импорт",
|
||||
"Import Recipe": "Импортировать рецепт",
|
||||
"ImportAll": "Импортировать всё",
|
||||
"ImportFirstRecipe": "",
|
||||
"ImportIntoTandoor": "Импорт в Tandoor",
|
||||
"ImportMealPlans": "",
|
||||
"ImportShoppingList": "",
|
||||
"Import_Error": "Во время импорта произошла ошибка. Для просмотра разверните \"Подробности\" в нижней части страницы.",
|
||||
"Import_Not_Yet_Supported": "Импорт пока не поддерживается",
|
||||
"Import_Result_Info": "{imported} из {total} рецептов были импортированы",
|
||||
@@ -284,6 +291,7 @@
|
||||
"Last": "Последний",
|
||||
"Last_name": "Фамилия",
|
||||
"Learn_More": "Узнать больше",
|
||||
"LeaveSpace": "",
|
||||
"Link": "Гиперссылка",
|
||||
"Load": "Загрузить",
|
||||
"Load_More": "Загрузить еще",
|
||||
@@ -358,6 +366,8 @@
|
||||
"Note": "Заметка",
|
||||
"Number of Objects": "Количество (шт.)",
|
||||
"Nutrition": "Питательность",
|
||||
"NutritionsPerServing": "",
|
||||
"NutritionsPerServingHelp": "",
|
||||
"OfflineAlert": "Вы находитесь вне сети, список покупок может не синхронизироваться.",
|
||||
"Ok": "Открыть",
|
||||
"OnHand": "В Наличии",
|
||||
@@ -494,17 +504,21 @@
|
||||
"Show_as_header": "Показывать как заголовок",
|
||||
"Single": "Одиночный",
|
||||
"Size": "Размер",
|
||||
"Skip": "",
|
||||
"Social_Authentication": "Социальная аутентификация",
|
||||
"Sort_by_new": "Сортировка по новизне",
|
||||
"Source": "Источник",
|
||||
"SourceImportHelp": "Импортируйте JSON в формате schema.org/recipe или HTML-страницы с рецептами в формате JSON-LD или микроданных.",
|
||||
"SourceImportSubtitle": "Импортировать JSON или HTML вручную.",
|
||||
"Space": "",
|
||||
"SpaceHelp": "",
|
||||
"SpaceLimitExceeded": "Ваше пространство превысило один из лимитов, некоторые функции могут быть ограничены.",
|
||||
"SpaceLimitReached": "В этом пространстве достигнут лимит. Новые объекты данного типа создавать нельзя.",
|
||||
"SpaceMemberHelp": "Для добавления пользователей создайте пригласительную ссылку и передайте её человеку, которого хотите пригласить.",
|
||||
"SpaceMembers": "Участники пространства",
|
||||
"SpaceMembersHelp": "Пользователи и их права доступа в пространстве. ",
|
||||
"SpaceMembersHelp": "",
|
||||
"SpaceName": "",
|
||||
"SpacePrivateObjectsHelp": "",
|
||||
"SpaceSettings": "Настройки пространства",
|
||||
"Space_Cosmetic_Settings": "Администраторы пространства могут менять некоторые визуальные настройки, которые будут переопределять настройки клиента для данного пространства.",
|
||||
"Split": "Разделить",
|
||||
@@ -614,6 +628,8 @@
|
||||
"Week": "Неделя",
|
||||
"Week_Numbers": "Номер недели",
|
||||
"Welcome": "Добро пожаловать",
|
||||
"WelcomeSettingsHelp": "",
|
||||
"WelcometoTandoor": "",
|
||||
"WorkingTime": "Время работы",
|
||||
"Year": "Год",
|
||||
"Yes": "",
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
"Access_Token": "Dostopni žeton",
|
||||
"Account": "Račun",
|
||||
"Actions": "Dejanja",
|
||||
"Active": "",
|
||||
"Activity": "Aktivnost",
|
||||
"Add": "Dodaj",
|
||||
"AddAll": "Dodaj vse",
|
||||
@@ -109,6 +110,8 @@
|
||||
"Create": "Ustvari",
|
||||
"Create Food": "Ustvari živilo",
|
||||
"Create Recipe": "Ustvari recept",
|
||||
"CreateFirstRecipe": "",
|
||||
"CreateInvitation": "",
|
||||
"Create_Meal_Plan_Entry": "Ustvari vnos za načrtovan obrok",
|
||||
"Create_New_Food": "Dodaj Novo Hrano",
|
||||
"Create_New_Keyword": "Dodaj novo ključno besedo",
|
||||
@@ -220,6 +223,7 @@
|
||||
"GettingStarted": "Začetek",
|
||||
"Global": "",
|
||||
"GlobalHelp": "",
|
||||
"Group": "",
|
||||
"GroupBy": "Združi po",
|
||||
"HeaderWarning": "Opozorilo: Sprememba naslova izbriše količino/enoto/hrano",
|
||||
"Headline": "Glavni naslov",
|
||||
@@ -245,7 +249,10 @@
|
||||
"Import": "Uvozi",
|
||||
"Import Recipe": "Uvozi recept",
|
||||
"ImportAll": "Uvozi vse",
|
||||
"ImportFirstRecipe": "",
|
||||
"ImportIntoTandoor": "Uvozi v Tandoor",
|
||||
"ImportMealPlans": "",
|
||||
"ImportShoppingList": "",
|
||||
"Import_Error": "Med uvozom je prišlo do napake. Za ogled razširite podrobnosti na dnu strani.",
|
||||
"Import_Not_Yet_Supported": "Uvoz še ni podprt",
|
||||
"Import_Result_Info": "Uvoženih je bilo {imported} od {total} receptov",
|
||||
@@ -284,6 +291,7 @@
|
||||
"Last": "Zadnji",
|
||||
"Last_name": "Priimek",
|
||||
"Learn_More": "Preberite Več",
|
||||
"LeaveSpace": "",
|
||||
"Link": "Hiperpovezava",
|
||||
"Load": "Naloži",
|
||||
"Load_More": "Naloži več",
|
||||
@@ -360,6 +368,8 @@
|
||||
"Note": "Opomba",
|
||||
"Number of Objects": "Število predmetov",
|
||||
"Nutrition": "Prehrana",
|
||||
"NutritionsPerServing": "",
|
||||
"NutritionsPerServingHelp": "",
|
||||
"OfflineAlert": "Si v načinu brez povezave, nakupovalni listek se mogoče ne bo sinhroniziral.",
|
||||
"Ok": "V redu",
|
||||
"OnHand": "Trenutno imam v roki",
|
||||
@@ -496,17 +506,21 @@
|
||||
"Show_as_header": "Prikaži kot glavo",
|
||||
"Single": "Ena",
|
||||
"Size": "Velikost",
|
||||
"Skip": "",
|
||||
"Social_Authentication": "Socialna avtentikacija",
|
||||
"Sort_by_new": "Razvrsti po novih",
|
||||
"Source": "Vir",
|
||||
"SourceImportHelp": "Uvozite JSON v formatu schema.org/recipe ali na straneh html z receptom json+ld ali mikropodatki.",
|
||||
"SourceImportSubtitle": "Ročno uvozite JSON ali HTML.",
|
||||
"Space": "",
|
||||
"SpaceHelp": "",
|
||||
"SpaceLimitExceeded": "Vaš prostor je presegel eno od svojih omejitev, nekatere funkcije so morda omejene.",
|
||||
"SpaceLimitReached": "Ta prostor je dosegel omejitev. Te vrste predmetov ni mogoče ustvariti več.",
|
||||
"SpaceMemberHelp": "Dodajte uporabnike v svoj prostor tako, da ustvarite povezavo za povabilo in jo pošljete osebi, ki jo želite dodati.",
|
||||
"SpaceMembers": "Člani prostora",
|
||||
"SpaceMembersHelp": "Uporabniki in njihova dovoljenja v prostoru. ",
|
||||
"SpaceMembersHelp": "",
|
||||
"SpaceName": "",
|
||||
"SpacePrivateObjectsHelp": "",
|
||||
"SpaceSettings": "Nastavitve prostora",
|
||||
"Space_Cosmetic_Settings": "Nekatere kozmetične nastavitve lahko spremenijo skrbniki prostora in bodo preglasile nastavitve odjemalca za ta prostor.",
|
||||
"Split": "Razdelitev",
|
||||
@@ -616,6 +630,8 @@
|
||||
"Week": "Teden",
|
||||
"Week_Numbers": "Števila tednov",
|
||||
"Welcome": "Dobrodošli",
|
||||
"WelcomeSettingsHelp": "",
|
||||
"WelcometoTandoor": "",
|
||||
"WorkingTime": "Delovni čas",
|
||||
"Year": "Leto",
|
||||
"Yes": "",
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
"Access_Token": "Åtkomstnyckel",
|
||||
"Account": "Konto",
|
||||
"Actions": "Åtgärder",
|
||||
"Active": "",
|
||||
"Activity": "Aktivitet",
|
||||
"Add": "Lägg till",
|
||||
"AddAll": "Lägg till alla",
|
||||
@@ -108,6 +109,8 @@
|
||||
"Create": "Skapa",
|
||||
"Create Food": "Skapa livsmedel",
|
||||
"Create Recipe": "Skapa recept",
|
||||
"CreateFirstRecipe": "",
|
||||
"CreateInvitation": "",
|
||||
"Create_Meal_Plan_Entry": "Skapa en måltidsplan",
|
||||
"Create_New_Food": "Lägg till nytt livsmedel",
|
||||
"Create_New_Keyword": "Lägg till nytt nyckelord",
|
||||
@@ -196,6 +199,7 @@
|
||||
"FuzzySearchHelp": "",
|
||||
"Global": "",
|
||||
"GlobalHelp": "",
|
||||
"Group": "",
|
||||
"GroupBy": "Gruppera enligt",
|
||||
"Hide_Food": "Dölj livsmedel",
|
||||
"Hide_Keyword": "Dölj nyckelord",
|
||||
@@ -214,6 +218,9 @@
|
||||
"Image": "Bild",
|
||||
"Import": "Importera",
|
||||
"Import Recipe": "Importera recept",
|
||||
"ImportFirstRecipe": "",
|
||||
"ImportMealPlans": "",
|
||||
"ImportShoppingList": "",
|
||||
"Import_Error": "Ett fel uppstod under din import. Expandera informationen längst ner på sidan för att se den.",
|
||||
"Import_Not_Yet_Supported": "Import stöds inte ännu",
|
||||
"Import_Result_Info": "{imported} av totalt {total} recept blev importerat",
|
||||
@@ -244,6 +251,7 @@
|
||||
"Language": "Språk",
|
||||
"Last_name": "Efternamn",
|
||||
"Learn_More": "Läs mer",
|
||||
"LeaveSpace": "",
|
||||
"Link": "Länk",
|
||||
"Load_More": "Ladda mer",
|
||||
"LogCredits": "",
|
||||
@@ -305,6 +313,8 @@
|
||||
"Note": "Anteckning",
|
||||
"Number of Objects": "Antal objekt",
|
||||
"Nutrition": "Näringsinnehåll",
|
||||
"NutritionsPerServing": "",
|
||||
"NutritionsPerServingHelp": "",
|
||||
"OfflineAlert": "Du är offline, inköpslistan kanske inte synkroniseras.",
|
||||
"Ok": "Öppna",
|
||||
"OnHand": "För närvarande till hands",
|
||||
@@ -398,9 +408,14 @@
|
||||
"Show_as_header": "Visa som rubrik",
|
||||
"Single": "Enstaka",
|
||||
"Size": "Storlek",
|
||||
"Skip": "",
|
||||
"Social_Authentication": "Social autentisering",
|
||||
"Sort_by_new": "Sortera efter ny",
|
||||
"Space": "",
|
||||
"SpaceHelp": "",
|
||||
"SpaceMembersHelp": "",
|
||||
"SpaceName": "",
|
||||
"SpacePrivateObjectsHelp": "",
|
||||
"Space_Cosmetic_Settings": "Vissa kosmetiska inställningar kan ändras av hushålls-administratörer och skriver över klientinställningar för det hushållet.",
|
||||
"Split_All_Steps": "Dela upp alla rader i separata steg.",
|
||||
"StartDate": "Startdatum",
|
||||
@@ -467,6 +482,8 @@
|
||||
"Week": "Vecka",
|
||||
"Week_Numbers": "Veckonummer",
|
||||
"Welcome": "Välkommen",
|
||||
"WelcomeSettingsHelp": "",
|
||||
"WelcometoTandoor": "",
|
||||
"Year": "År",
|
||||
"Yes": "",
|
||||
"add_keyword": "Lägg till nyckelord",
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
"API_Browser": "",
|
||||
"API_Documentation": "",
|
||||
"Account": "Hesap",
|
||||
"Active": "",
|
||||
"Add": "Ekle",
|
||||
"AddChild": "",
|
||||
"AddFoodToShopping": "{food}'ı alışveriş listenize ekleyin",
|
||||
@@ -74,6 +75,8 @@
|
||||
"Create": "Oluştur",
|
||||
"Create Food": "Yiyecek Oluştur",
|
||||
"Create Recipe": "Tarif Oluştur",
|
||||
"CreateFirstRecipe": "",
|
||||
"CreateInvitation": "",
|
||||
"Create_Meal_Plan_Entry": "Yemek planı girişi oluştur",
|
||||
"Create_New_Food": "Yeni Yiyecek Ekle",
|
||||
"Create_New_Keyword": "Yeni Anahtar Kelime Ekle",
|
||||
@@ -159,6 +162,7 @@
|
||||
"FuzzySearchHelp": "",
|
||||
"Global": "",
|
||||
"GlobalHelp": "",
|
||||
"Group": "",
|
||||
"GroupBy": "Gruplandırma Ölçütü",
|
||||
"Hide_Food": "Yiyeceği Gizle",
|
||||
"Hide_Keyword": "Anahtar kelimeleri gizle",
|
||||
@@ -177,6 +181,9 @@
|
||||
"Image": "Resim",
|
||||
"Import": "İçeriye Aktar",
|
||||
"Import Recipe": "Tarif İçe Aktar",
|
||||
"ImportFirstRecipe": "",
|
||||
"ImportMealPlans": "",
|
||||
"ImportShoppingList": "",
|
||||
"Import_Error": "İçeri aktarma sırasında bir hata oluştu. Görüntülemek için lütfen sayfanın altındaki Ayrıntıları genişletin.",
|
||||
"Import_Not_Yet_Supported": "İçe aktarma henüz desteklenmiyor",
|
||||
"Import_Result_Info": "{total} tariften {imported} tanesi içe aktarıldı",
|
||||
@@ -207,6 +214,7 @@
|
||||
"Language": "Dil",
|
||||
"Last_name": "Soyisim",
|
||||
"Learn_More": "Daha Fazla",
|
||||
"LeaveSpace": "",
|
||||
"Link": "Bağlantı",
|
||||
"Load_More": "Daha Fazla Yükle",
|
||||
"LogCredits": "",
|
||||
@@ -268,6 +276,8 @@
|
||||
"Note": "Not",
|
||||
"Number of Objects": "Nesne Sayısı",
|
||||
"Nutrition": "Besin Değeri",
|
||||
"NutritionsPerServing": "",
|
||||
"NutritionsPerServingHelp": "",
|
||||
"OfflineAlert": "Çevrimdışısınız, alışveriş listesi senkronize edilemeyebilir.",
|
||||
"Ok": "Tamam",
|
||||
"OnHand": "Şu anda Elinizde",
|
||||
@@ -361,9 +371,14 @@
|
||||
"Show_as_header": "Başlık olarak göster",
|
||||
"Single": "Tek",
|
||||
"Size": "Boyut",
|
||||
"Skip": "",
|
||||
"Social_Authentication": "Sosyal Kimlik Doğrulama",
|
||||
"Sort_by_new": "Yeniye göre sırala",
|
||||
"Space": "",
|
||||
"SpaceHelp": "",
|
||||
"SpaceMembersHelp": "",
|
||||
"SpaceName": "",
|
||||
"SpacePrivateObjectsHelp": "",
|
||||
"Space_Cosmetic_Settings": "Bazı kozmetik ayarlar alan yöneticileri tarafından değiştirilebilir ve o alanın istemci ayarlarını geçersiz kılar.",
|
||||
"Split_All_Steps": "Tüm satırları ayrı adımlara bölün.",
|
||||
"StartDate": "Başlangıç Tarihi",
|
||||
@@ -430,6 +445,8 @@
|
||||
"Week": "Hafta",
|
||||
"Week_Numbers": "Hafta numaraları",
|
||||
"Welcome": "Hoşgeldiniz",
|
||||
"WelcomeSettingsHelp": "",
|
||||
"WelcometoTandoor": "",
|
||||
"Year": "Yıl",
|
||||
"Yes": "",
|
||||
"add_keyword": "Anahtar Kelime Ekle",
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"AISettingsHostedHelp": "",
|
||||
"API_Browser": "",
|
||||
"API_Documentation": "",
|
||||
"Active": "",
|
||||
"Add": "Додати",
|
||||
"AddChild": "",
|
||||
"AddFoodToShopping": "Додати {food} до вашого списку покупок",
|
||||
@@ -65,6 +66,8 @@
|
||||
"CountMore": "...+{count} більше",
|
||||
"Create": "Створити",
|
||||
"Create Food": "",
|
||||
"CreateFirstRecipe": "",
|
||||
"CreateInvitation": "",
|
||||
"Create_Meal_Plan_Entry": "Створити запис в плані харчування",
|
||||
"Create_New_Food": "Додати Нову Їжу",
|
||||
"Create_New_Keyword": "Додати Нове Ключове слово",
|
||||
@@ -140,6 +143,7 @@
|
||||
"FuzzySearchHelp": "",
|
||||
"Global": "",
|
||||
"GlobalHelp": "",
|
||||
"Group": "",
|
||||
"GroupBy": "По Групі",
|
||||
"Hide_Food": "Сховати Їжу",
|
||||
"Hide_Keyword": "",
|
||||
@@ -155,6 +159,9 @@
|
||||
"IgnoredFood": "{food} ігнорується в покупках.",
|
||||
"Image": "Зображення",
|
||||
"Import": "Імпорт",
|
||||
"ImportFirstRecipe": "",
|
||||
"ImportMealPlans": "",
|
||||
"ImportShoppingList": "",
|
||||
"Import_Error": "",
|
||||
"Import_Not_Yet_Supported": "",
|
||||
"Import_Result_Info": "",
|
||||
@@ -182,6 +189,7 @@
|
||||
"Keywords": "Ключові слова",
|
||||
"Language": "Мова",
|
||||
"Learn_More": "Дізнатися Більше",
|
||||
"LeaveSpace": "",
|
||||
"Link": "Посилання",
|
||||
"Load_More": "Завантажити більше",
|
||||
"LogCredits": "",
|
||||
@@ -234,6 +242,8 @@
|
||||
"Note": "Нотатка",
|
||||
"Number of Objects": "Кількість Об'єктів",
|
||||
"Nutrition": "Харчова цінність",
|
||||
"NutritionsPerServing": "",
|
||||
"NutritionsPerServingHelp": "",
|
||||
"OfflineAlert": "Ви офлайн, список покупок може не синхронізуватися.",
|
||||
"Ok": "Відкрити",
|
||||
"OnHand": "Зараз На Руках",
|
||||
@@ -319,8 +329,13 @@
|
||||
"Show_as_header": "Показати як заголовок",
|
||||
"Single": "",
|
||||
"Size": "Розмір",
|
||||
"Skip": "",
|
||||
"Sort_by_new": "Сортувати за новими",
|
||||
"Space": "",
|
||||
"SpaceHelp": "",
|
||||
"SpaceMembersHelp": "",
|
||||
"SpaceName": "",
|
||||
"SpacePrivateObjectsHelp": "",
|
||||
"StartDate": "Початкова дата",
|
||||
"Starting_Day": "Початковий день тижня",
|
||||
"StartsWith": "",
|
||||
@@ -373,6 +388,8 @@
|
||||
"Week": "Неділя",
|
||||
"Week_Numbers": "Номер тижня",
|
||||
"Welcome": "Вітаємо",
|
||||
"WelcomeSettingsHelp": "",
|
||||
"WelcometoTandoor": "",
|
||||
"Year": "Рік",
|
||||
"Yes": "",
|
||||
"add_keyword": "",
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
"API_Browser": "",
|
||||
"API_Documentation": "",
|
||||
"Account": "账户",
|
||||
"Active": "",
|
||||
"Add": "添加",
|
||||
"AddChild": "",
|
||||
"AddFoodToShopping": "添加 {food} 到购物清单",
|
||||
@@ -74,6 +75,8 @@
|
||||
"Create": "创建",
|
||||
"Create Food": "创建食物",
|
||||
"Create Recipe": "创建食谱",
|
||||
"CreateFirstRecipe": "",
|
||||
"CreateInvitation": "",
|
||||
"Create_Meal_Plan_Entry": "创建用餐计划条目",
|
||||
"Create_New_Food": "添加新的食物",
|
||||
"Create_New_Keyword": "添加新的关键词",
|
||||
@@ -159,6 +162,7 @@
|
||||
"FuzzySearchHelp": "",
|
||||
"Global": "",
|
||||
"GlobalHelp": "",
|
||||
"Group": "",
|
||||
"GroupBy": "分组",
|
||||
"Hide_Food": "隐藏食物",
|
||||
"Hide_Keyword": "隐藏关键词",
|
||||
@@ -177,6 +181,9 @@
|
||||
"Image": "图片",
|
||||
"Import": "导入",
|
||||
"Import Recipe": "导入食谱",
|
||||
"ImportFirstRecipe": "",
|
||||
"ImportMealPlans": "",
|
||||
"ImportShoppingList": "",
|
||||
"Import_Error": "导入时发生错误。 请跳转至页面底部的详细信息进行查看。",
|
||||
"Import_Not_Yet_Supported": "导入尚未支持",
|
||||
"Import_Result_Info": "导入 {imported} 个,共 {total} 个食谱已导入",
|
||||
@@ -207,6 +214,7 @@
|
||||
"Language": "语言",
|
||||
"Last_name": "姓",
|
||||
"Learn_More": "了解更多",
|
||||
"LeaveSpace": "",
|
||||
"Link": "链接",
|
||||
"Load_More": "加载更多",
|
||||
"LogCredits": "",
|
||||
@@ -268,6 +276,8 @@
|
||||
"Note": "笔记",
|
||||
"Number of Objects": "对象数量",
|
||||
"Nutrition": "营养",
|
||||
"NutritionsPerServing": "",
|
||||
"NutritionsPerServingHelp": "",
|
||||
"OfflineAlert": "您处于离线状态,购物清单可能无法同步。",
|
||||
"Ok": "确认",
|
||||
"OnHand": "目前",
|
||||
@@ -361,9 +371,14 @@
|
||||
"Show_as_header": "显示标题",
|
||||
"Single": "单个",
|
||||
"Size": "大小",
|
||||
"Skip": "",
|
||||
"Social_Authentication": "社交认证",
|
||||
"Sort_by_new": "按新旧排序",
|
||||
"Space": "",
|
||||
"SpaceHelp": "",
|
||||
"SpaceMembersHelp": "",
|
||||
"SpaceName": "",
|
||||
"SpacePrivateObjectsHelp": "",
|
||||
"Space_Cosmetic_Settings": "空间管理员可以更改某些装饰设置,并将覆盖该空间的客户端设置。",
|
||||
"Split_All_Steps": "将所有行拆分为单独的步骤。",
|
||||
"StartDate": "开始日期",
|
||||
@@ -430,6 +445,8 @@
|
||||
"Week": "星期",
|
||||
"Week_Numbers": "周数",
|
||||
"Welcome": "欢迎",
|
||||
"WelcomeSettingsHelp": "",
|
||||
"WelcometoTandoor": "",
|
||||
"Year": "年",
|
||||
"Yes": "",
|
||||
"add_keyword": "添加关键字",
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
"Access_Token": "訪問令牌",
|
||||
"Account": "賬戶",
|
||||
"Actions": "動作",
|
||||
"Active": "",
|
||||
"Activity": "活動",
|
||||
"Add": "新增",
|
||||
"AddAll": "增加全部",
|
||||
@@ -108,6 +109,8 @@
|
||||
"Create": "建立",
|
||||
"Create Food": "建立食物",
|
||||
"Create Recipe": "建立食譜",
|
||||
"CreateFirstRecipe": "",
|
||||
"CreateInvitation": "",
|
||||
"Create_Meal_Plan_Entry": "建立餐飲計劃條目",
|
||||
"Create_New_Food": "建立新食物",
|
||||
"Create_New_Keyword": "建立新關鍵字",
|
||||
@@ -219,6 +222,7 @@
|
||||
"GettingStarted": "開始使用",
|
||||
"Global": "",
|
||||
"GlobalHelp": "",
|
||||
"Group": "",
|
||||
"GroupBy": "分組依據",
|
||||
"HeaderWarning": "警告:變更為標題會刪除數量/單位/食物",
|
||||
"Headline": "標題",
|
||||
@@ -244,7 +248,10 @@
|
||||
"Import": "匯入",
|
||||
"Import Recipe": "匯入食譜",
|
||||
"ImportAll": "全部匯入",
|
||||
"ImportFirstRecipe": "",
|
||||
"ImportIntoTandoor": "匯入到 Tandoor",
|
||||
"ImportMealPlans": "",
|
||||
"ImportShoppingList": "",
|
||||
"Import_Error": "導入時發生錯誤。 請跳轉至頁面底部的詳細資訊進行查看。",
|
||||
"Import_Not_Yet_Supported": "匯入尚不支援",
|
||||
"Import_Result_Info": "匯入結果資訊",
|
||||
@@ -283,6 +290,7 @@
|
||||
"Last": "最後",
|
||||
"Last_name": "姓",
|
||||
"Learn_More": "了解更多",
|
||||
"LeaveSpace": "",
|
||||
"Link": "連結",
|
||||
"Load": "載入",
|
||||
"Load_More": "載入更多",
|
||||
@@ -359,6 +367,8 @@
|
||||
"Note": "備註",
|
||||
"Number of Objects": "對象數量",
|
||||
"Nutrition": "營養",
|
||||
"NutritionsPerServing": "",
|
||||
"NutritionsPerServingHelp": "",
|
||||
"OfflineAlert": "您處於離線狀態,購物清單可能無法同步。",
|
||||
"Ok": "確定",
|
||||
"OnHand": "手頭有",
|
||||
@@ -495,17 +505,21 @@
|
||||
"Show_as_header": "顯示為標題",
|
||||
"Single": "單一",
|
||||
"Size": "大小",
|
||||
"Skip": "",
|
||||
"Social_Authentication": "社交認證",
|
||||
"Sort_by_new": "按最新排序",
|
||||
"Source": "來源",
|
||||
"SourceImportHelp": "匯入 schema.org/recipe 格式的 JSON 或包含 json+ld 食譜或微資料的 HTML 頁面。",
|
||||
"SourceImportSubtitle": "手動匯入 JSON 或 HTML。",
|
||||
"Space": "",
|
||||
"SpaceHelp": "",
|
||||
"SpaceLimitExceeded": "您的空間已超過其中一個限制,某些功能可能會受到限制。",
|
||||
"SpaceLimitReached": "此空間已達到限制。無法再建立此類型的物件。",
|
||||
"SpaceMemberHelp": "透過建立邀請連結並發送給您要新增的人來將使用者新增到您的空間。",
|
||||
"SpaceMembers": "空間成員",
|
||||
"SpaceMembersHelp": "空間中的使用者及其權限。 ",
|
||||
"SpaceMembersHelp": "",
|
||||
"SpaceName": "",
|
||||
"SpacePrivateObjectsHelp": "",
|
||||
"SpaceSettings": "空間設定",
|
||||
"Space_Cosmetic_Settings": "空間管理員可以更改某些裝飾設置,並將覆蓋該空間的客戶端設置。",
|
||||
"Split": "分割",
|
||||
@@ -615,6 +629,8 @@
|
||||
"Week": "週",
|
||||
"Week_Numbers": "週數",
|
||||
"Welcome": "歡迎",
|
||||
"WelcomeSettingsHelp": "",
|
||||
"WelcometoTandoor": "",
|
||||
"WorkingTime": "製作時間",
|
||||
"Year": "年",
|
||||
"Yes": "",
|
||||
|
||||
@@ -1785,6 +1785,10 @@ export interface ApiShoppingListRecipeUpdateRequest {
|
||||
shoppingListRecipe: Omit<ShoppingListRecipe, 'recipeData'|'mealPlanData'|'createdBy'>;
|
||||
}
|
||||
|
||||
export interface ApiSpaceCreateRequest {
|
||||
space?: Omit<Space, 'createdBy'|'createdAt'|'maxRecipes'|'maxFileStorageMb'|'maxUsers'|'allowSharing'|'demo'|'userCount'|'recipeCount'|'fileSizeMb'|'aiMonthlyCreditsUsed'>;
|
||||
}
|
||||
|
||||
export interface ApiSpaceListRequest {
|
||||
page?: number;
|
||||
pageSize?: number;
|
||||
@@ -1799,6 +1803,11 @@ export interface ApiSpaceRetrieveRequest {
|
||||
id: number;
|
||||
}
|
||||
|
||||
export interface ApiSpaceUpdateRequest {
|
||||
id: number;
|
||||
space?: Omit<Space, 'createdBy'|'createdAt'|'maxRecipes'|'maxFileStorageMb'|'maxUsers'|'allowSharing'|'demo'|'userCount'|'recipeCount'|'fileSizeMb'|'aiMonthlyCreditsUsed'>;
|
||||
}
|
||||
|
||||
export interface ApiStepCreateRequest {
|
||||
step: Omit<Step, 'instructionsMarkdown'|'stepRecipeData'|'numrecipe'>;
|
||||
}
|
||||
@@ -2139,6 +2148,11 @@ export interface ApiUserRetrieveRequest {
|
||||
id: number;
|
||||
}
|
||||
|
||||
export interface ApiUserSpaceAllPersonalListRequest {
|
||||
page?: number;
|
||||
pageSize?: number;
|
||||
}
|
||||
|
||||
export interface ApiUserSpaceDestroyRequest {
|
||||
id: number;
|
||||
}
|
||||
@@ -13083,6 +13097,39 @@ export class ApiApi extends runtime.BaseAPI {
|
||||
return await response.value();
|
||||
}
|
||||
|
||||
/**
|
||||
* logs request counts to redis cache total/per user/
|
||||
*/
|
||||
async apiSpaceCreateRaw(requestParameters: ApiSpaceCreateRequest, initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise<runtime.ApiResponse<Space>> {
|
||||
const queryParameters: any = {};
|
||||
|
||||
const headerParameters: runtime.HTTPHeaders = {};
|
||||
|
||||
headerParameters['Content-Type'] = 'application/json';
|
||||
|
||||
if (this.configuration && this.configuration.apiKey) {
|
||||
headerParameters["Authorization"] = await this.configuration.apiKey("Authorization"); // ApiKeyAuth authentication
|
||||
}
|
||||
|
||||
const response = await this.request({
|
||||
path: `/api/space/`,
|
||||
method: 'POST',
|
||||
headers: headerParameters,
|
||||
query: queryParameters,
|
||||
body: SpaceToJSON(requestParameters['space']),
|
||||
}, initOverrides);
|
||||
|
||||
return new runtime.JSONApiResponse(response, (jsonValue) => SpaceFromJSON(jsonValue));
|
||||
}
|
||||
|
||||
/**
|
||||
* logs request counts to redis cache total/per user/
|
||||
*/
|
||||
async apiSpaceCreate(requestParameters: ApiSpaceCreateRequest = {}, initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise<Space> {
|
||||
const response = await this.apiSpaceCreateRaw(requestParameters, initOverrides);
|
||||
return await response.value();
|
||||
}
|
||||
|
||||
/**
|
||||
* logs request counts to redis cache total/per user/
|
||||
*/
|
||||
@@ -13228,6 +13275,46 @@ export class ApiApi extends runtime.BaseAPI {
|
||||
return await response.value();
|
||||
}
|
||||
|
||||
/**
|
||||
* logs request counts to redis cache total/per user/
|
||||
*/
|
||||
async apiSpaceUpdateRaw(requestParameters: ApiSpaceUpdateRequest, initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise<runtime.ApiResponse<Space>> {
|
||||
if (requestParameters['id'] == null) {
|
||||
throw new runtime.RequiredError(
|
||||
'id',
|
||||
'Required parameter "id" was null or undefined when calling apiSpaceUpdate().'
|
||||
);
|
||||
}
|
||||
|
||||
const queryParameters: any = {};
|
||||
|
||||
const headerParameters: runtime.HTTPHeaders = {};
|
||||
|
||||
headerParameters['Content-Type'] = 'application/json';
|
||||
|
||||
if (this.configuration && this.configuration.apiKey) {
|
||||
headerParameters["Authorization"] = await this.configuration.apiKey("Authorization"); // ApiKeyAuth authentication
|
||||
}
|
||||
|
||||
const response = await this.request({
|
||||
path: `/api/space/{id}/`.replace(`{${"id"}}`, encodeURIComponent(String(requestParameters['id']))),
|
||||
method: 'PUT',
|
||||
headers: headerParameters,
|
||||
query: queryParameters,
|
||||
body: SpaceToJSON(requestParameters['space']),
|
||||
}, initOverrides);
|
||||
|
||||
return new runtime.JSONApiResponse(response, (jsonValue) => SpaceFromJSON(jsonValue));
|
||||
}
|
||||
|
||||
/**
|
||||
* logs request counts to redis cache total/per user/
|
||||
*/
|
||||
async apiSpaceUpdate(requestParameters: ApiSpaceUpdateRequest, initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise<Space> {
|
||||
const response = await this.apiSpaceUpdateRaw(requestParameters, initOverrides);
|
||||
return await response.value();
|
||||
}
|
||||
|
||||
/**
|
||||
* logs request counts to redis cache total/per user/
|
||||
*/
|
||||
@@ -16152,6 +16239,44 @@ export class ApiApi extends runtime.BaseAPI {
|
||||
return await response.value();
|
||||
}
|
||||
|
||||
/**
|
||||
* return all userspaces for the user requesting the endpoint :param request: :return:
|
||||
*/
|
||||
async apiUserSpaceAllPersonalListRaw(requestParameters: ApiUserSpaceAllPersonalListRequest, initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise<runtime.ApiResponse<PaginatedUserSpaceList>> {
|
||||
const queryParameters: any = {};
|
||||
|
||||
if (requestParameters['page'] != null) {
|
||||
queryParameters['page'] = requestParameters['page'];
|
||||
}
|
||||
|
||||
if (requestParameters['pageSize'] != null) {
|
||||
queryParameters['page_size'] = requestParameters['pageSize'];
|
||||
}
|
||||
|
||||
const headerParameters: runtime.HTTPHeaders = {};
|
||||
|
||||
if (this.configuration && this.configuration.apiKey) {
|
||||
headerParameters["Authorization"] = await this.configuration.apiKey("Authorization"); // ApiKeyAuth authentication
|
||||
}
|
||||
|
||||
const response = await this.request({
|
||||
path: `/api/user-space/all_personal/`,
|
||||
method: 'GET',
|
||||
headers: headerParameters,
|
||||
query: queryParameters,
|
||||
}, initOverrides);
|
||||
|
||||
return new runtime.JSONApiResponse(response, (jsonValue) => PaginatedUserSpaceListFromJSON(jsonValue));
|
||||
}
|
||||
|
||||
/**
|
||||
* return all userspaces for the user requesting the endpoint :param request: :return:
|
||||
*/
|
||||
async apiUserSpaceAllPersonalList(requestParameters: ApiUserSpaceAllPersonalListRequest = {}, initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise<PaginatedUserSpaceList> {
|
||||
const response = await this.apiUserSpaceAllPersonalListRaw(requestParameters, initOverrides);
|
||||
return await response.value();
|
||||
}
|
||||
|
||||
/**
|
||||
* logs request counts to redis cache total/per user/
|
||||
*/
|
||||
|
||||
@@ -248,6 +248,12 @@ export interface PatchedSpace {
|
||||
* @memberof PatchedSpace
|
||||
*/
|
||||
aiDefaultProvider?: AiProvider;
|
||||
/**
|
||||
*
|
||||
* @type {boolean}
|
||||
* @memberof PatchedSpace
|
||||
*/
|
||||
spaceSetupCompleted?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -299,6 +305,7 @@ export function PatchedSpaceFromJSONTyped(json: any, ignoreDiscriminator: boolea
|
||||
'aiMonthlyCreditsUsed': json['ai_monthly_credits_used'] == null ? undefined : json['ai_monthly_credits_used'],
|
||||
'aiEnabled': json['ai_enabled'] == null ? undefined : json['ai_enabled'],
|
||||
'aiDefaultProvider': json['ai_default_provider'] == null ? undefined : AiProviderFromJSON(json['ai_default_provider']),
|
||||
'spaceSetupCompleted': json['space_setup_completed'] == null ? undefined : json['space_setup_completed'],
|
||||
};
|
||||
}
|
||||
|
||||
@@ -329,6 +336,7 @@ export function PatchedSpaceToJSON(value?: Omit<PatchedSpace, 'createdBy'|'creat
|
||||
'ai_credits_balance': value['aiCreditsBalance'],
|
||||
'ai_enabled': value['aiEnabled'],
|
||||
'ai_default_provider': AiProviderToJSON(value['aiDefaultProvider']),
|
||||
'space_setup_completed': value['spaceSetupCompleted'],
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -121,7 +121,7 @@ export interface Space {
|
||||
* @type {Array<FoodInheritField>}
|
||||
* @memberof Space
|
||||
*/
|
||||
foodInherit: Array<FoodInheritField>;
|
||||
foodInherit?: Array<FoodInheritField>;
|
||||
/**
|
||||
*
|
||||
* @type {number}
|
||||
@@ -248,6 +248,12 @@ export interface Space {
|
||||
* @memberof Space
|
||||
*/
|
||||
aiDefaultProvider?: AiProvider;
|
||||
/**
|
||||
*
|
||||
* @type {boolean}
|
||||
* @memberof Space
|
||||
*/
|
||||
spaceSetupCompleted?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -261,7 +267,6 @@ export function instanceOfSpace(value: object): value is Space {
|
||||
if (!('maxUsers' in value) || value['maxUsers'] === undefined) return false;
|
||||
if (!('allowSharing' in value) || value['allowSharing'] === undefined) return false;
|
||||
if (!('demo' in value) || value['demo'] === undefined) return false;
|
||||
if (!('foodInherit' in value) || value['foodInherit'] === undefined) return false;
|
||||
if (!('userCount' in value) || value['userCount'] === undefined) return false;
|
||||
if (!('recipeCount' in value) || value['recipeCount'] === undefined) return false;
|
||||
if (!('fileSizeMb' in value) || value['fileSizeMb'] === undefined) return false;
|
||||
@@ -289,7 +294,7 @@ export function SpaceFromJSONTyped(json: any, ignoreDiscriminator: boolean): Spa
|
||||
'maxUsers': json['max_users'],
|
||||
'allowSharing': json['allow_sharing'],
|
||||
'demo': json['demo'],
|
||||
'foodInherit': ((json['food_inherit'] as Array<any>).map(FoodInheritFieldFromJSON)),
|
||||
'foodInherit': json['food_inherit'] == null ? undefined : ((json['food_inherit'] as Array<any>).map(FoodInheritFieldFromJSON)),
|
||||
'userCount': json['user_count'],
|
||||
'recipeCount': json['recipe_count'],
|
||||
'fileSizeMb': json['file_size_mb'],
|
||||
@@ -311,6 +316,7 @@ export function SpaceFromJSONTyped(json: any, ignoreDiscriminator: boolean): Spa
|
||||
'aiMonthlyCreditsUsed': json['ai_monthly_credits_used'],
|
||||
'aiEnabled': json['ai_enabled'] == null ? undefined : json['ai_enabled'],
|
||||
'aiDefaultProvider': json['ai_default_provider'] == null ? undefined : AiProviderFromJSON(json['ai_default_provider']),
|
||||
'spaceSetupCompleted': json['space_setup_completed'] == null ? undefined : json['space_setup_completed'],
|
||||
};
|
||||
}
|
||||
|
||||
@@ -323,7 +329,7 @@ export function SpaceToJSON(value?: Omit<Space, 'createdBy'|'createdAt'|'maxReci
|
||||
'id': value['id'],
|
||||
'name': value['name'],
|
||||
'message': value['message'],
|
||||
'food_inherit': ((value['foodInherit'] as Array<any>).map(FoodInheritFieldToJSON)),
|
||||
'food_inherit': value['foodInherit'] == null ? undefined : ((value['foodInherit'] as Array<any>).map(FoodInheritFieldToJSON)),
|
||||
'image': UserFileViewToJSON(value['image']),
|
||||
'nav_logo': UserFileViewToJSON(value['navLogo']),
|
||||
'space_theme': SpaceThemeEnumToJSON(value['spaceTheme']),
|
||||
@@ -341,6 +347,7 @@ export function SpaceToJSON(value?: Omit<Space, 'createdBy'|'createdAt'|'maxReci
|
||||
'ai_credits_balance': value['aiCreditsBalance'],
|
||||
'ai_enabled': value['aiEnabled'],
|
||||
'ai_default_provider': AiProviderToJSON(value['aiDefaultProvider']),
|
||||
'space_setup_completed': value['spaceSetupCompleted'],
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -35,6 +35,17 @@
|
||||
<database-model-col model="MealType"></database-model-col>
|
||||
</v-row>
|
||||
|
||||
<v-row>
|
||||
<v-col>
|
||||
<h2>{{ $t('Space') }}</h2>
|
||||
</v-col>
|
||||
</v-row>
|
||||
<v-row dense>
|
||||
<database-model-col model="Space"></database-model-col>
|
||||
<database-model-col model="UserSpace"></database-model-col>
|
||||
<database-model-col model="InviteLink"></database-model-col>
|
||||
</v-row>
|
||||
|
||||
<template v-if="useUserPreferenceStore().activeSpace.aiEnabled">
|
||||
<v-row>
|
||||
<v-col>
|
||||
|
||||
@@ -34,16 +34,19 @@
|
||||
</v-card-actions>
|
||||
|
||||
<v-card-text v-if="genericModel.model.name == 'AiLog'">
|
||||
{{ $t('MonthlyCreditsUsed') }} ({{ useUserPreferenceStore().activeSpace.aiMonthlyCreditsUsed }} / {{ useUserPreferenceStore().activeSpace.aiCreditsMonthly }})
|
||||
{{ $t('MonthlyCreditsUsed') }} ({{ useUserPreferenceStore().activeSpace.aiMonthlyCreditsUsed }} / {{
|
||||
useUserPreferenceStore().activeSpace.aiCreditsMonthly
|
||||
}})
|
||||
{{ $t('AiCreditsBalance') }} : {{ useUserPreferenceStore().activeSpace.aiCreditsBalance }}
|
||||
<v-progress-linear :model-value="useUserPreferenceStore().activeSpace.aiMonthlyCreditsUsed" :max="useUserPreferenceStore().activeSpace.aiCreditsMonthly"></v-progress-linear>
|
||||
<v-progress-linear :model-value="useUserPreferenceStore().activeSpace.aiMonthlyCreditsUsed"
|
||||
:max="useUserPreferenceStore().activeSpace.aiCreditsMonthly"></v-progress-linear>
|
||||
</v-card-text>
|
||||
</v-card>
|
||||
</v-col>
|
||||
</v-row>
|
||||
<v-row>
|
||||
<v-col>
|
||||
<v-text-field prepend-inner-icon="$search" :label="$t('Search')" v-model="query" clearable></v-text-field>
|
||||
<v-text-field prepend-inner-icon="$search" :label="$t('Search')" v-model="query" v-if="!genericModel.model.disableSearch" clearable></v-text-field>
|
||||
|
||||
<v-data-table-server
|
||||
v-model="selectedItems"
|
||||
@@ -82,13 +85,20 @@
|
||||
<v-chip label v-if="item.space == null" color="success">{{ $t('Global') }}</v-chip>
|
||||
<v-chip label v-else color="info">{{ $t('Space') }}</v-chip>
|
||||
</template>
|
||||
<template v-slot:item.groups="{ item }" v-if="genericModel.model.name == 'UserSpace'">
|
||||
{{ item.groups.flatMap((x: Group) => x.name).join(', ') }}
|
||||
</template>
|
||||
<template v-slot:item.active="{ item }" v-if="genericModel.model.name == 'Space'">
|
||||
<v-chip label v-if="item.id == useUserPreferenceStore().activeSpace.id!" color="success">{{ $t('Active') }}</v-chip>
|
||||
<v-chip label v-else color="info" @click="useUserPreferenceStore().switchSpace(item)">{{ $t('Select') }}</v-chip>
|
||||
</template>
|
||||
<template v-slot:item.action="{ item }">
|
||||
<v-btn class="float-right" icon="$menu" variant="plain">
|
||||
<v-icon icon="$menu"></v-icon>
|
||||
<v-menu activator="parent" close-on-content-click>
|
||||
<v-list density="compact">
|
||||
<v-list-item prepend-icon="$edit" :to="{name: 'ModelEditPage', params: {model: model, id: item.id}}"
|
||||
v-if="!genericModel.model.disableCreate && !genericModel.model.disableUpdate && !genericModel.model.disableDelete">
|
||||
v-if="!(genericModel.model.disableCreate && genericModel.model.disableUpdate && genericModel.model.disableDelete)">
|
||||
{{ $t('Edit') }}
|
||||
</v-list-item>
|
||||
<v-list-item prepend-icon="fa-solid fa-arrows-to-dot" v-if="genericModel.model.isMerge" link>
|
||||
@@ -111,6 +121,11 @@
|
||||
<v-list-item prepend-icon="fa-solid fa-rotate" v-if="genericModel.model.name == 'RecipeImport'" @click="importRecipe(item)">
|
||||
{{ $t('Import') }}
|
||||
</v-list-item>
|
||||
<v-list-item prepend-icon="fa-solid fa-arrow-right-from-bracket"
|
||||
v-if="genericModel.model.name == 'Space' && item.createdBy.id != useUserPreferenceStore().userSettings.user.id!"
|
||||
@click="leaveSpace(item)">
|
||||
{{ $t('LeaveSpace') }}
|
||||
</v-list-item>
|
||||
</v-list>
|
||||
</v-menu>
|
||||
</v-btn>
|
||||
@@ -144,7 +159,7 @@ import {useUserPreferenceStore} from "@/stores/UserPreferenceStore";
|
||||
import ModelMergeDialog from "@/components/dialogs/ModelMergeDialog.vue";
|
||||
import {VDataTableUpdateOptions} from "@/vuetify";
|
||||
import SyncDialog from "@/components/dialogs/SyncDialog.vue";
|
||||
import {ApiApi, ApiRecipeListRequest, RecipeImport} from "@/openapi";
|
||||
import {ApiApi, ApiRecipeListRequest, Group, RecipeImport, Space, UserSpace} from "@/openapi";
|
||||
import {useTitle} from "@vueuse/core";
|
||||
import RecipeShareDialog from "@/components/dialogs/RecipeShareDialog.vue";
|
||||
import AddToShoppingDialog from "@/components/dialogs/AddToShoppingDialog.vue";
|
||||
@@ -261,6 +276,26 @@ function importAllRecipes() {
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* leave the selected space as a user
|
||||
* @param space to leave
|
||||
*/
|
||||
function leaveSpace(space: Space) {
|
||||
let api = new ApiApi()
|
||||
useUserPreferenceStore().userSpaces.forEach((us: UserSpace) => {
|
||||
if (us.space == space.id!) {
|
||||
loading.value = true
|
||||
api.apiUserSpaceDestroy({id: us.id!}).then(r => {
|
||||
|
||||
}).catch(err => {
|
||||
useMessageStore().addError(ErrorMessageType.DELETE_ERROR, err)
|
||||
}).finally(() => {
|
||||
loading.value = false
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
@@ -141,14 +141,14 @@
|
||||
|
||||
<div v-if="importType == 'ai'">
|
||||
<v-row>
|
||||
<v-col md="6">
|
||||
<ModelSelect model="AiProvider" v-model="selectedAiProvider">
|
||||
<v-col cols="12" md="6">
|
||||
<ModelSelect model="AiProvider" v-model="selectedAiProvider" hide-details>
|
||||
<template #append>
|
||||
<v-btn icon="$settings" :to="{name:'ModelListPage', params: {model: 'AiProvider'}}" color="success"></v-btn>
|
||||
</template>
|
||||
</ModelSelect>
|
||||
</v-col>
|
||||
<v-col md="6">
|
||||
<v-col cols="12" md="6">
|
||||
<v-btn-toggle class="mb-2" border divided v-model="aiMode">
|
||||
<v-btn value="file">{{ $t('File') }}</v-btn>
|
||||
<v-btn value="text">{{ $t('Text') }}</v-btn>
|
||||
@@ -250,7 +250,7 @@
|
||||
|
||||
<v-row>
|
||||
<v-col>
|
||||
<model-select model="Keyword" v-model="keywordSelect">
|
||||
<model-select model="Keyword" v-model="keywordSelect" allow-create>
|
||||
<template #append>
|
||||
<v-btn icon="$add" color="success"
|
||||
@click="keywordSelect.importKeyword = true; importResponse.recipe.keywords.push(keywordSelect); keywordSelect= null"
|
||||
@@ -434,6 +434,11 @@
|
||||
<v-checkbox v-model="appImportDuplicates"></v-checkbox>
|
||||
</template>
|
||||
</v-alert>
|
||||
<div v-if="importApp == 'MEALIE1'">
|
||||
<v-checkbox v-model="appImportMealPlans" :label="$t('ImportMealPlans')" hide-details></v-checkbox>
|
||||
<v-checkbox v-model="appImportShoppingLists" :label="$t('ImportShoppingList')" hide-details></v-checkbox>
|
||||
<v-checkbox v-model="appImportNutritionsPerServing" :label="$t('NutritionsPerServing')" :hint="$t('NutritionsPerServingHelp')" persistent-hint></v-checkbox>
|
||||
</div>
|
||||
|
||||
<v-stepper-actions>
|
||||
<template #prev>
|
||||
@@ -658,6 +663,9 @@ const urlListImportedRecipes = ref([] as Recipe[])
|
||||
const sourceImportText = ref("")
|
||||
const appImportFiles = ref<File[]>([])
|
||||
const appImportDuplicates = ref(false)
|
||||
const appImportMealPlans = ref(true)
|
||||
const appImportShoppingLists = ref(true)
|
||||
const appImportNutritionsPerServing = ref(false)
|
||||
const appImportLog = ref<null | ImportLog>(null)
|
||||
const image = ref<null | File>(null)
|
||||
const aiMode = ref<'file' | 'text'>('file')
|
||||
@@ -770,7 +778,7 @@ function loadRecipeFromAiImport() {
|
||||
}
|
||||
|
||||
function appImport() {
|
||||
doAppImport(appImportFiles.value, importApp.value, appImportDuplicates.value).then(r => {
|
||||
doAppImport(appImportFiles.value, importApp.value, appImportDuplicates.value, appImportMealPlans.value, appImportShoppingLists.value, appImportNutritionsPerServing.value).then(r => {
|
||||
stepper.value = 'import_log'
|
||||
recLoadImportLog(r)
|
||||
})
|
||||
|
||||
@@ -13,9 +13,7 @@
|
||||
<v-list-item :to="{name: 'SearchSettings'}" prepend-icon="$search">{{ $t('Search') }}</v-list-item>
|
||||
<v-divider></v-divider>
|
||||
<v-list-subheader>Space</v-list-subheader>
|
||||
<v-list-item :to="{name: 'UserSpaceSettings'}" prepend-icon="$spaces">{{ $t('YourSpaces') }}</v-list-item>
|
||||
<v-list-item :to="{name: 'SpaceSettings'}" prepend-icon="$settings">{{ $t('SpaceSettings') }}</v-list-item>
|
||||
<v-list-item :to="{name: 'SpaceMemberSettings'}" prepend-icon="fa-solid fa-users">{{ $t('SpaceMembers') }}</v-list-item>
|
||||
<v-list-item :to="{name: 'OpenDataImportSettings'}" prepend-icon="fa-solid fa-cloud-arrow-down">{{ $t('Open_Data_Import') }}</v-list-item>
|
||||
<v-list-item :to="{name: 'ExportDataSettings'}" prepend-icon="fa-solid fa-file-export">{{ $t('Export') }}</v-list-item>
|
||||
<v-divider></v-divider>
|
||||
|
||||
@@ -3,29 +3,53 @@
|
||||
<horizontal-meal-plan-window v-if="useUserPreferenceStore().deviceSettings.start_showMealPlan"></horizontal-meal-plan-window>
|
||||
|
||||
<v-card v-if="totalRecipes == 0" class="mt-5 mb-5">
|
||||
<v-card-title><i class="fa-solid fa-eye-slash"></i> {{ $t('search_no_recipes') }}</v-card-title>
|
||||
<v-card-title class="text-center"><i class="fa-solid fa-eye-slash"></i> {{ $t('search_no_recipes') }}</v-card-title>
|
||||
<v-card-text>
|
||||
<v-btn-group divided>
|
||||
<v-btn size="large" color="success" prepend-icon="$create" :to="{ name: 'ModelEditPage', params: {model: 'recipe'} }">{{ $t('Create Recipe') }}</v-btn>
|
||||
<v-btn size="large" color="primary" prepend-icon="fa-solid fa-globe" :to="{ name: 'RecipeImportPage', params: {} }">{{ $t('Import Recipe') }}</v-btn>
|
||||
</v-btn-group>
|
||||
<v-card
|
||||
:title="$t('Create Recipe')"
|
||||
variant="outlined"
|
||||
:to="{name: 'ModelEditPage', params: {model: 'Recipe'}}"
|
||||
prepend-icon="$recipes"
|
||||
append-icon="fa-solid fa-arrow-right"
|
||||
class="mb-4">
|
||||
<template #subtitle>
|
||||
<p class="text-wrap">
|
||||
{{ $t('CreateFirstRecipe') }}
|
||||
</p>
|
||||
</template>
|
||||
</v-card>
|
||||
|
||||
<v-card
|
||||
:title="$t('Import')"
|
||||
variant="outlined"
|
||||
:to="{name: 'RecipeImportPage', params: {}}"
|
||||
prepend-icon="$import"
|
||||
append-icon="fa-solid fa-arrow-right">
|
||||
<template #subtitle>
|
||||
<p class="text-wrap">
|
||||
{{ $t('ImportFirstRecipe') }}
|
||||
</p>
|
||||
</template>
|
||||
</v-card>
|
||||
</v-card-text>
|
||||
</v-card>
|
||||
<template v-if="totalRecipes > 0">
|
||||
<horizontal-recipe-scroller :skeletons="4" mode="recent" v-if="totalRecipes > 5"></horizontal-recipe-scroller>
|
||||
<horizontal-recipe-scroller :skeletons="4" mode="new"></horizontal-recipe-scroller>
|
||||
<horizontal-recipe-scroller :skeletons="4" mode="keyword" v-if="totalRecipes > 10"></horizontal-recipe-scroller>
|
||||
<horizontal-recipe-scroller :skeletons="4" mode="random" v-if="totalRecipes > 10"></horizontal-recipe-scroller>
|
||||
<horizontal-recipe-scroller :skeletons="4" mode="created_by" v-if="totalRecipes > 5"></horizontal-recipe-scroller>
|
||||
<horizontal-recipe-scroller :skeletons="2" mode="rating" v-if="totalRecipes > 5"></horizontal-recipe-scroller>
|
||||
<horizontal-recipe-scroller :skeletons="4" mode="keyword" v-if="totalRecipes > 5"></horizontal-recipe-scroller>
|
||||
<horizontal-recipe-scroller :skeletons="4" mode="random" v-if="totalRecipes > 25"></horizontal-recipe-scroller>
|
||||
|
||||
<horizontal-recipe-scroller :skeletons="4" mode="recent"></horizontal-recipe-scroller>
|
||||
<horizontal-recipe-scroller :skeletons="4" mode="new"></horizontal-recipe-scroller>
|
||||
<horizontal-recipe-scroller :skeletons="4" mode="keyword"></horizontal-recipe-scroller>
|
||||
<horizontal-recipe-scroller :skeletons="4" mode="random"></horizontal-recipe-scroller>
|
||||
<horizontal-recipe-scroller :skeletons="4" mode="created_by"></horizontal-recipe-scroller>
|
||||
<horizontal-recipe-scroller :skeletons="2" mode="rating"></horizontal-recipe-scroller>
|
||||
<horizontal-recipe-scroller :skeletons="4" mode="keyword"></horizontal-recipe-scroller>
|
||||
<horizontal-recipe-scroller :skeletons="4" mode="random"></horizontal-recipe-scroller>
|
||||
<v-row>
|
||||
<v-col class="text-center">
|
||||
<v-btn size="x-large" rounded="xl" prepend-icon="$search" variant="tonal" :to="{name: 'SearchPage', params: {query: ''}}">{{ $t('View_Recipes') }}</v-btn>
|
||||
</v-col>
|
||||
</v-row>
|
||||
|
||||
<v-row>
|
||||
<v-col class="text-center">
|
||||
<v-btn size="x-large" rounded="xl" prepend-icon="$search" variant="tonal" :to="{name: 'SearchPage', params: {query: ''}}">{{ $t('View_Recipes') }}</v-btn>
|
||||
</v-col>
|
||||
</v-row>
|
||||
</template>
|
||||
|
||||
|
||||
</v-container>
|
||||
@@ -38,6 +62,7 @@ import HorizontalRecipeScroller from "@/components/display/HorizontalRecipeWindo
|
||||
import HorizontalMealPlanWindow from "@/components/display/HorizontalMealPlanWindow.vue"
|
||||
import SearchPage from "@/pages/SearchPage.vue";
|
||||
import {useUserPreferenceStore} from "@/stores/UserPreferenceStore";
|
||||
import {useRouter} from "vue-router";
|
||||
|
||||
const totalRecipes = ref(-1)
|
||||
|
||||
|
||||
255
vue3/src/pages/WelcomePage.vue
Normal file
255
vue3/src/pages/WelcomePage.vue
Normal file
@@ -0,0 +1,255 @@
|
||||
<template>
|
||||
<v-container>
|
||||
|
||||
|
||||
<v-stepper editable v-model="stepper">
|
||||
<v-stepper-header>
|
||||
|
||||
<v-stepper-item :title="$t('Settings')" value="1"></v-stepper-item>
|
||||
<v-divider></v-divider>
|
||||
<v-stepper-item :title="$t('Open Data')" value="2"></v-stepper-item>
|
||||
<v-divider></v-divider>
|
||||
<v-stepper-item :title="$t('Invites')" value="3"></v-stepper-item>
|
||||
<v-divider></v-divider>
|
||||
<v-stepper-item :title="$t('GettingStarted')" value="4"></v-stepper-item>
|
||||
</v-stepper-header>
|
||||
|
||||
<v-stepper-window>
|
||||
<v-stepper-window-item value="1">
|
||||
<v-card flat>
|
||||
<v-card-title class="text-h4">{{ $t('WelcometoTandoor') }} <span class="text-tandoor">{{useUserPreferenceStore().userSettings.user.displayName}}</span></v-card-title>
|
||||
<v-card-text v-if="space">
|
||||
<p class="text-subtitle-1 mb-4">{{ $t('WelcomeSettingsHelp') }}</p>
|
||||
|
||||
<v-text-field v-model="space.name" :label="$t('Name')"></v-text-field>
|
||||
|
||||
<v-select :label="$t('Theme')" v-model="useUserPreferenceStore().userSettings.theme"
|
||||
:items="[{title: 'Tandoor', value: 'TANDOOR'}, {title: 'Tandoor Dark', value: 'TANDOOR_DARK'}, ]">
|
||||
</v-select>
|
||||
|
||||
<v-text-field v-model="useUserPreferenceStore().userSettings.defaultUnit" :label="$t('Default_Unit')"></v-text-field>
|
||||
|
||||
<v-checkbox :label="$t('Use_Fractions')" :hint="$t('Use_Fractions_Help')" persistent-hint v-model="useUserPreferenceStore().userSettings.useFractions"></v-checkbox>
|
||||
|
||||
</v-card-text>
|
||||
</v-card>
|
||||
|
||||
<v-stepper-actions>
|
||||
<template #prev>
|
||||
<v-spacer></v-spacer>
|
||||
</template>
|
||||
<template #next>
|
||||
<v-btn @click="finishWelcome()" color="warning" class="me-2" :loading="loading">{{ $t('Skip') }}</v-btn>
|
||||
<v-btn @click="updateSpaceAndUserSettings()" :loading="loading" color="success">{{ $t('Next') }}</v-btn>
|
||||
</template>
|
||||
</v-stepper-actions>
|
||||
|
||||
</v-stepper-window-item>
|
||||
|
||||
<v-stepper-window-item value="2">
|
||||
<v-card flat>
|
||||
<v-card-text>
|
||||
<open-data-import-settings></open-data-import-settings>
|
||||
</v-card-text>
|
||||
</v-card>
|
||||
|
||||
<v-stepper-actions>
|
||||
<template #prev>
|
||||
<v-btn @click="stepper = '1'">{{ $t('Back') }}</v-btn>
|
||||
</template>
|
||||
<template #next>
|
||||
<v-btn @click="stepper = '3'" color="success">{{ $t('Next') }}</v-btn>
|
||||
</template>
|
||||
</v-stepper-actions>
|
||||
|
||||
</v-stepper-window-item>
|
||||
|
||||
<v-stepper-window-item value="3">
|
||||
<v-card flat>
|
||||
<v-card-text class="text-center">
|
||||
<v-card variant="outlined">
|
||||
<v-card-title class="text-h4 pb-0 mb-0 text-center">{{ $t('Space') }}</v-card-title>
|
||||
<v-card-subtitle class="text-subtitle-1 text-center mb-4">{{ $t('SpaceHelp') }}</v-card-subtitle>
|
||||
<v-card-text>
|
||||
<v-row>
|
||||
<v-col class="text-center" v-for="model in [TRecipe, TFood, TUnit, TSupermarket, TKeyword]">
|
||||
<v-icon :icon="model.icon" size="x-large"></v-icon>
|
||||
<p class="text-h6">{{ $t(model.localizationKey) }}</p>
|
||||
</v-col>
|
||||
<v-col class="text-center">
|
||||
<v-icon icon="fa-solid fa-ellipsis" size="x-large"></v-icon>
|
||||
<p class="text-h6">{{ $t('More') }}</p>
|
||||
</v-col>
|
||||
</v-row>
|
||||
|
||||
<div class="border-md border-opacity-75 border-dotted rounded mt-5 w-md-75 ml-auto mr-auto">
|
||||
<v-card-subtitle class="text-subtitle-1 text-center mb-4 mt-2 text-wrap">
|
||||
{{ $t('SpacePrivateObjectsHelp') }}
|
||||
</v-card-subtitle>
|
||||
<v-row>
|
||||
<v-col class="text-center" v-for="model in [TMealPlan, TShoppingListEntry, TRecipeBook]">
|
||||
<v-icon :icon="model.icon" size="x-large"></v-icon>
|
||||
<p class="text-h6">{{ $t(model.localizationKey) }}</p>
|
||||
</v-col>
|
||||
</v-row>
|
||||
</div>
|
||||
</v-card-text>
|
||||
</v-card>
|
||||
|
||||
<v-btn size="x-large" class="mt-4" variant="outlined">{{ $t('CreateInvitation') }}
|
||||
<model-edit-dialog model="InviteLink" :close-after-create="false" :close-after-save="false"></model-edit-dialog>
|
||||
</v-btn>
|
||||
</v-card-text>
|
||||
</v-card>
|
||||
|
||||
<v-stepper-actions>
|
||||
<template #prev>
|
||||
<v-btn @click="stepper = '2'" color="success">{{ $t('Back') }}</v-btn>
|
||||
</template>
|
||||
<template #next>
|
||||
<v-btn @click="stepper = '4'" color="success">{{ $t('Next') }}</v-btn>
|
||||
</template>
|
||||
</v-stepper-actions>
|
||||
</v-stepper-window-item>
|
||||
|
||||
<v-stepper-window-item value="4">
|
||||
<v-card flat>
|
||||
|
||||
<v-card-text>
|
||||
|
||||
<v-card
|
||||
:title="$t('Create Recipe')"
|
||||
variant="outlined"
|
||||
@click="finishWelcome({name: 'ModelEditPage', params: {model: 'Recipe'}})"
|
||||
prepend-icon="$recipes"
|
||||
append-icon="fa-solid fa-arrow-right"
|
||||
class="mb-4">
|
||||
<template #subtitle>
|
||||
<p class="text-wrap">
|
||||
{{ $t('CreateFirstRecipe') }}
|
||||
</p>
|
||||
</template>
|
||||
</v-card>
|
||||
|
||||
<v-card
|
||||
:title="$t('Import')"
|
||||
variant="outlined"
|
||||
@click="finishWelcome({name: 'RecipeImportPage', params: {}})"
|
||||
prepend-icon="$import"
|
||||
append-icon="fa-solid fa-arrow-right">
|
||||
<template #subtitle>
|
||||
<p class="text-wrap">
|
||||
{{ $t('ImportFirstRecipe') }}
|
||||
</p>
|
||||
</template>
|
||||
</v-card>
|
||||
|
||||
|
||||
</v-card-text>
|
||||
</v-card>
|
||||
|
||||
<v-stepper-actions>
|
||||
<template #prev>
|
||||
<v-btn @click="stepper = '2'" color="success">{{ $t('Back') }}</v-btn>
|
||||
</template>
|
||||
<template #next>
|
||||
<v-btn @click="finishWelcome()" color="success" :disabled="false">{{ $t('Finish') }}</v-btn>
|
||||
</template>
|
||||
</v-stepper-actions>
|
||||
|
||||
</v-stepper-window-item>
|
||||
|
||||
</v-stepper-window>
|
||||
|
||||
</v-stepper>
|
||||
|
||||
</v-container>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
|
||||
|
||||
import {ApiApi, Space} from "@/openapi";
|
||||
import {onMounted, ref} from "vue";
|
||||
import {ErrorMessageType, MessageType, useMessageStore} from "@/stores/MessageStore.ts";
|
||||
import {useUserPreferenceStore} from "@/stores/UserPreferenceStore.ts";
|
||||
import OpenDataImportSettings from "@/components/settings/OpenDataImportSettings.vue";
|
||||
import {TFood, TKeyword, TMealPlan, TRecipe, TRecipeBook, TShoppingListEntry, TSupermarket, TUnit} from "@/types/Models.ts";
|
||||
import ModelEditDialog from "@/components/dialogs/ModelEditDialog.vue";
|
||||
import {RouteLocationRaw, useRouter} from "vue-router";
|
||||
|
||||
const router = useRouter()
|
||||
|
||||
const space = ref<undefined | Space>(undefined)
|
||||
const stepper = ref("1")
|
||||
const loading = ref(false)
|
||||
|
||||
onMounted(() => {
|
||||
loadSpace()
|
||||
})
|
||||
|
||||
/**
|
||||
* save setup completion and redirect to target page
|
||||
* @param target
|
||||
*/
|
||||
function finishWelcome(target: RouteLocationRaw = {name: 'StartPage'}) {
|
||||
if (space.value) {
|
||||
space.value.spaceSetupCompleted = true
|
||||
loading.value = true
|
||||
updateSpace().then(() => {
|
||||
router.push(target)
|
||||
loading.value = false
|
||||
})
|
||||
} else {
|
||||
useMessageStore().addMessage(MessageType.ERROR, "Space not loaded yet", 5000)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* load active space data
|
||||
*/
|
||||
function loadSpace() {
|
||||
let api = new ApiApi()
|
||||
|
||||
api.apiSpaceCurrentRetrieve().then(r => {
|
||||
space.value = r
|
||||
}).catch(err => {
|
||||
useMessageStore().addError(ErrorMessageType.FETCH_ERROR, err)
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* update both the space and user settings
|
||||
*/
|
||||
function updateSpaceAndUserSettings() {
|
||||
let promises = [] as Promise<any>[]
|
||||
loading.value = true
|
||||
|
||||
promises.push(updateSpace())
|
||||
promises.push(useUserPreferenceStore().updateUserSettings(true))
|
||||
|
||||
Promise.allSettled(promises).then(r => {
|
||||
loading.value = false
|
||||
stepper.value = "2"
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* update space in database
|
||||
*/
|
||||
function updateSpace() {
|
||||
let api = new ApiApi()
|
||||
return api.apiSpacePartialUpdate({id: space.value.id, patchedSpace: space.value}).then(r => {
|
||||
space.value = r
|
||||
useUserPreferenceStore().activeSpace = Object.assign({}, space.value)
|
||||
}).catch(err => {
|
||||
useMessageStore().addError(ErrorMessageType.UPDATE_ERROR, err)
|
||||
})
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
|
||||
</style>
|
||||
@@ -67,7 +67,7 @@ export const useUserPreferenceStore = defineStore('user_preference_store', () =>
|
||||
function loadUserSettings() {
|
||||
console.log('loading user settings from DB')
|
||||
let api = new ApiApi()
|
||||
api.apiUserPreferenceList().then(r => {
|
||||
return api.apiUserPreferenceList().then(r => {
|
||||
if (r.length == 1) {
|
||||
userSettings.value = r[0]
|
||||
isAuthenticated.value = true
|
||||
@@ -85,13 +85,15 @@ export const useUserPreferenceStore = defineStore('user_preference_store', () =>
|
||||
/**
|
||||
* persist changes to user settings to DB
|
||||
*/
|
||||
function updateUserSettings() {
|
||||
function updateUserSettings(silent: boolean = false) {
|
||||
let api = new ApiApi()
|
||||
|
||||
api.apiUserPreferencePartialUpdate({user: userSettings.value.user.id!, patchedUserPreference: userSettings.value}).then(r => {
|
||||
return api.apiUserPreferencePartialUpdate({user: userSettings.value.user.id!, patchedUserPreference: userSettings.value}).then(r => {
|
||||
userSettings.value = r
|
||||
updateTheme()
|
||||
useMessageStore().addPreparedMessage(PreparedMessage.UPDATE_SUCCESS)
|
||||
if (!silent) {
|
||||
useMessageStore().addPreparedMessage(PreparedMessage.UPDATE_SUCCESS)
|
||||
}
|
||||
}).catch(err => {
|
||||
useMessageStore().addError(ErrorMessageType.UPDATE_ERROR, err)
|
||||
})
|
||||
@@ -102,7 +104,7 @@ export const useUserPreferenceStore = defineStore('user_preference_store', () =>
|
||||
*/
|
||||
function loadServerSettings() {
|
||||
let api = new ApiApi()
|
||||
api.apiServerSettingsCurrentRetrieve().then(r => {
|
||||
return api.apiServerSettingsCurrentRetrieve().then(r => {
|
||||
serverSettings.value = r
|
||||
}).catch(err => {
|
||||
useMessageStore().addError(ErrorMessageType.FETCH_ERROR, err)
|
||||
@@ -114,7 +116,7 @@ export const useUserPreferenceStore = defineStore('user_preference_store', () =>
|
||||
*/
|
||||
function loadActiveSpace() {
|
||||
let api = new ApiApi()
|
||||
api.apiSpaceCurrentRetrieve().then(r => {
|
||||
return api.apiSpaceCurrentRetrieve().then(r => {
|
||||
activeSpace.value = r
|
||||
}).catch(err => {
|
||||
if (err.response.status != 403) {
|
||||
@@ -128,7 +130,7 @@ export const useUserPreferenceStore = defineStore('user_preference_store', () =>
|
||||
*/
|
||||
function loadUserSpaces() {
|
||||
let api = new ApiApi()
|
||||
api.apiUserSpaceList().then(r => {
|
||||
return api.apiUserSpaceAllPersonalList().then(r => {
|
||||
userSpaces.value = r.results
|
||||
}).catch(err => {
|
||||
if (err.response.status != 403) {
|
||||
@@ -144,7 +146,7 @@ export const useUserPreferenceStore = defineStore('user_preference_store', () =>
|
||||
function loadSpaces() {
|
||||
let api = new ApiApi()
|
||||
|
||||
api.apiSpaceList().then(r => {
|
||||
return api.apiSpaceList().then(r => {
|
||||
spaces.value = r.results
|
||||
}).catch(err => {
|
||||
if (err.response.status != 403) {
|
||||
@@ -160,9 +162,10 @@ export const useUserPreferenceStore = defineStore('user_preference_store', () =>
|
||||
let api = new ApiApi()
|
||||
|
||||
api.apiSwitchActiveSpaceRetrieve({spaceId: space.id!}).then(r => {
|
||||
loadActiveSpace()
|
||||
router.push({name: 'StartPage'}).then(() => {
|
||||
location.reload()
|
||||
loadActiveSpace().then(() => {
|
||||
router.push({name: 'StartPage'}).then(() => {
|
||||
location.reload()
|
||||
})
|
||||
})
|
||||
}).catch(err => {
|
||||
useMessageStore().addError(ErrorMessageType.FETCH_ERROR, err)
|
||||
@@ -221,15 +224,20 @@ export const useUserPreferenceStore = defineStore('user_preference_store', () =>
|
||||
}
|
||||
}
|
||||
|
||||
// always load settings on first initialization of store
|
||||
loadUserSettings()
|
||||
loadServerSettings()
|
||||
loadActiveSpace()
|
||||
loadUserSpaces()
|
||||
loadSpaces()
|
||||
updateTheme()
|
||||
function init() {
|
||||
const promises = [] as Promise<any>[]
|
||||
promises.push(loadUserSettings())
|
||||
promises.push(loadServerSettings())
|
||||
promises.push(loadActiveSpace())
|
||||
promises.push(loadUserSpaces())
|
||||
promises.push(loadSpaces())
|
||||
updateTheme()
|
||||
|
||||
return Promise.allSettled(promises)
|
||||
}
|
||||
|
||||
return {
|
||||
init,
|
||||
deviceSettings,
|
||||
userSettings,
|
||||
serverSettings,
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
import {
|
||||
AccessToken, AiLog, AiProvider,
|
||||
ApiApi, ApiKeywordMoveUpdateRequest, Automation, type AutomationTypeEnum, ConnectorConfig, CookLog, CustomFilter,
|
||||
Food,
|
||||
Food, FoodInheritField,
|
||||
Ingredient,
|
||||
InviteLink, Keyword,
|
||||
MealPlan,
|
||||
MealType,
|
||||
Property, PropertyType,
|
||||
Recipe, RecipeBook, RecipeBookEntry, RecipeImport, SearchFields, ShoppingListEntry,
|
||||
Recipe, RecipeBook, RecipeBookEntry, RecipeImport, SearchFields, ShoppingListEntry, Space,
|
||||
Step,
|
||||
Supermarket,
|
||||
SupermarketCategory, Sync, SyncLog,
|
||||
@@ -101,6 +101,7 @@ export type Model = {
|
||||
disableCreate?: boolean | undefined,
|
||||
disableUpdate?: boolean | undefined,
|
||||
disableDelete?: boolean | undefined,
|
||||
disableSearch?: boolean | undefined,
|
||||
// disable showing this model as an option in the ModelListPage
|
||||
disableListView?: boolean | undefined,
|
||||
|
||||
@@ -148,6 +149,8 @@ export type EditorSupportedModels =
|
||||
| 'SearchFields'
|
||||
| 'AiProvider'
|
||||
| 'AiLog'
|
||||
| 'Space'
|
||||
| 'FoodInheritField'
|
||||
|
||||
// used to type methods/parameters in conjunction with configuration type
|
||||
export type EditorSupportedTypes =
|
||||
@@ -184,6 +187,8 @@ export type EditorSupportedTypes =
|
||||
| SearchFields
|
||||
| AiProvider
|
||||
| AiLog
|
||||
| Space
|
||||
| FoodInheritField
|
||||
|
||||
export const TFood = {
|
||||
name: 'Food',
|
||||
@@ -655,7 +660,8 @@ export const TUserSpace = {
|
||||
disableCreate: true,
|
||||
|
||||
tableHeaders: [
|
||||
{title: 'User', key: 'user'},
|
||||
{title: 'User', key: 'user.displayName'},
|
||||
{title: 'Group', key: 'groups'},
|
||||
{title: 'Actions', key: 'action', align: 'end'},
|
||||
]
|
||||
} as Model
|
||||
@@ -669,19 +675,40 @@ export const TInviteLink = {
|
||||
|
||||
editorComponent: defineAsyncComponent(() => import(`@/components/model_editors/InviteLinkEditor.vue`)),
|
||||
|
||||
disableListView: true,
|
||||
disableSearch: true,
|
||||
isPaginated: true,
|
||||
toStringKeys: ['email', 'role'],
|
||||
|
||||
tableHeaders: [
|
||||
{title: 'Email', key: 'email'},
|
||||
{title: 'Role', key: 'group'},
|
||||
{title: 'Role', key: 'group.name'},
|
||||
{title: 'Valid Until', key: 'validUntil'},
|
||||
{title: 'Actions', key: 'action', align: 'end'},
|
||||
]
|
||||
} as Model
|
||||
registerModel(TInviteLink)
|
||||
|
||||
export const TSpace = {
|
||||
name: 'Space',
|
||||
localizationKey: 'Space',
|
||||
localizationKeyDescription: 'SpaceHelp',
|
||||
icon: 'fa-solid fa-hard-drive',
|
||||
|
||||
editorComponent: defineAsyncComponent(() => import(`@/components/model_editors/SpaceEditor.vue`)),
|
||||
|
||||
disableDelete: true,
|
||||
isPaginated: true,
|
||||
toStringKeys: ['name'],
|
||||
|
||||
tableHeaders: [
|
||||
{title: 'Name', key: 'name'},
|
||||
{title: 'Owner', key: 'createdBy.displayName'},
|
||||
{title: 'Active', key: 'active'},
|
||||
{title: 'Actions', key: 'action', align: 'end'},
|
||||
]
|
||||
} as Model
|
||||
registerModel(TSpace)
|
||||
|
||||
export const TStorage = {
|
||||
name: 'Storage',
|
||||
localizationKey: 'Storage',
|
||||
|
||||
@@ -17,7 +17,8 @@ export const INTEGRATIONS: Array<Integration> = [
|
||||
{id: 'COOKMATE', name: "Cookmate", import: true, export: false, helpUrl: 'https://docs.tandoor.dev/features/import_export/#cookmate'},
|
||||
{id: 'COPYMETHAT', name: "CopyMeThat", import: true, export: false, helpUrl: 'https://docs.tandoor.dev/features/import_export/#copymethat'},
|
||||
{id: 'DOMESTICA', name: "Domestica", import: true, export: false, helpUrl: 'https://docs.tandoor.dev/features/import_export/#domestica'},
|
||||
{id: 'MEALIE', name: "Mealie", import: true, export: false, helpUrl: 'https://docs.tandoor.dev/features/import_export/#mealie'},
|
||||
{id: 'MEALIE', name: "Mealie 0.x", import: true, export: false, helpUrl: 'https://docs.tandoor.dev/features/import_export/#mealie'},
|
||||
{id: 'MEALIE1', name: "Mealie 1.x", import: true, export: false, helpUrl: 'https://docs.tandoor.dev/features/import_export/#mealie'},
|
||||
{id: 'MEALMASTER', name: "Mealmaster", import: true, export: false, helpUrl: 'https://docs.tandoor.dev/features/import_export/#mealmaster'},
|
||||
{id: 'MELARECIPES', name: "Melarecipes", import: true, export: false, helpUrl: 'https://docs.tandoor.dev/features/import_export/#melarecipes'},
|
||||
{id: 'NEXTCLOUD', name: "Nextcloud Cookbook", import: true, export: true, helpUrl: 'https://docs.tandoor.dev/features/import_export/#nextcloud'},
|
||||
|
||||
389
vue3/yarn.lock
389
vue3/yarn.lock
@@ -959,26 +959,26 @@
|
||||
resolved "https://registry.yarnpkg.com/@fortawesome/fontawesome-free/-/fontawesome-free-6.7.2.tgz#8249de9b7e22fcb3ceb5e66090c30a1d5492b81a"
|
||||
integrity sha512-JUOtgFW6k9u4Y+xeIaEiLr3+cjoUPiAuLXoyKOJSia6Duzb7pq+A76P9ZdPDoAoxHdHzq6gE9/jKBGXlZT8FbA==
|
||||
|
||||
"@intlify/core-base@11.1.10":
|
||||
version "11.1.10"
|
||||
resolved "https://registry.yarnpkg.com/@intlify/core-base/-/core-base-11.1.10.tgz#4731748992bc6d8e723ca6c2cc5aa5a4c90cf7a5"
|
||||
integrity sha512-JhRb40hD93Vk0BgMgDc/xMIFtdXPHoytzeK6VafBNOj6bb6oUZrGamXkBKecMsmGvDQQaPRGG2zpa25VCw8pyw==
|
||||
"@intlify/core-base@11.1.11":
|
||||
version "11.1.11"
|
||||
resolved "https://registry.yarnpkg.com/@intlify/core-base/-/core-base-11.1.11.tgz#e36893a7d37a3a75fae30977fc58c1d8cf3c853f"
|
||||
integrity sha512-1Z0N8jTfkcD2Luq9HNZt+GmjpFe4/4PpZF3AOzoO1u5PTtSuXZcfhwBatywbfE2ieB/B5QHIoOFmCXY2jqVKEQ==
|
||||
dependencies:
|
||||
"@intlify/message-compiler" "11.1.10"
|
||||
"@intlify/shared" "11.1.10"
|
||||
"@intlify/message-compiler" "11.1.11"
|
||||
"@intlify/shared" "11.1.11"
|
||||
|
||||
"@intlify/message-compiler@11.1.10":
|
||||
version "11.1.10"
|
||||
resolved "https://registry.yarnpkg.com/@intlify/message-compiler/-/message-compiler-11.1.10.tgz#ff5c92c311cd72144126f5c128912adb4e911207"
|
||||
integrity sha512-TABl3c8tSLWbcD+jkQTyBhrnW251dzqW39MPgEUCsd69Ua3ceoimsbIzvkcPzzZvt1QDxNkenMht+5//V3JvLQ==
|
||||
"@intlify/message-compiler@11.1.11":
|
||||
version "11.1.11"
|
||||
resolved "https://registry.yarnpkg.com/@intlify/message-compiler/-/message-compiler-11.1.11.tgz#ba10641f86af0e991ac9def0385bd345c8f150fb"
|
||||
integrity sha512-7PC6neomoc/z7a8JRjPBbu0T2TzR2MQuY5kn2e049MP7+o32Ve7O8husylkA7K9fQRe4iNXZWTPnDJ6vZdtS1Q==
|
||||
dependencies:
|
||||
"@intlify/shared" "11.1.10"
|
||||
"@intlify/shared" "11.1.11"
|
||||
source-map-js "^1.0.2"
|
||||
|
||||
"@intlify/shared@11.1.10":
|
||||
version "11.1.10"
|
||||
resolved "https://registry.yarnpkg.com/@intlify/shared/-/shared-11.1.10.tgz#d869aa8fbc1aa307f26a58848fea6df3c9785b6f"
|
||||
integrity sha512-6ZW/f3Zzjxfa1Wh0tYQI5pLKUtU+SY7l70pEG+0yd0zjcsYcK0EBt6Fz30Dy0tZhEqemziQQy2aNU3GJzyrMUA==
|
||||
"@intlify/shared@11.1.11":
|
||||
version "11.1.11"
|
||||
resolved "https://registry.yarnpkg.com/@intlify/shared/-/shared-11.1.11.tgz#6bba3b86617c05767356e4ca939c9e300563a083"
|
||||
integrity sha512-RIBFTIqxZSsxUqlcyoR7iiC632bq7kkOwYvZlvcVObHfrF4NhuKc4FKvu8iPCrEO+e3XsY7/UVpfgzg+M7ETzA==
|
||||
|
||||
"@jridgewell/gen-mapping@^0.3.5":
|
||||
version "0.3.8"
|
||||
@@ -1079,105 +1079,110 @@
|
||||
estree-walker "^2.0.2"
|
||||
picomatch "^4.0.2"
|
||||
|
||||
"@rollup/rollup-android-arm-eabi@4.44.0":
|
||||
version "4.44.0"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.44.0.tgz#a3e4e4b2baf0bade6918cf5135c3ef7eee653196"
|
||||
integrity sha512-xEiEE5oDW6tK4jXCAyliuntGR+amEMO7HLtdSshVuhFnKTYoeYMyXQK7pLouAJJj5KHdwdn87bfHAR2nSdNAUA==
|
||||
"@rollup/rollup-android-arm-eabi@4.50.1":
|
||||
version "4.50.1"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.50.1.tgz#7d41dc45adcfcb272504ebcea9c8a5b2c659e963"
|
||||
integrity sha512-HJXwzoZN4eYTdD8bVV22DN8gsPCAj3V20NHKOs8ezfXanGpmVPR7kalUHd+Y31IJp9stdB87VKPFbsGY3H/2ag==
|
||||
|
||||
"@rollup/rollup-android-arm64@4.44.0":
|
||||
version "4.44.0"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.44.0.tgz#63566b0e76c62d4f96d44448f38a290562280200"
|
||||
integrity sha512-uNSk/TgvMbskcHxXYHzqwiyBlJ/lGcv8DaUfcnNwict8ba9GTTNxfn3/FAoFZYgkaXXAdrAA+SLyKplyi349Jw==
|
||||
"@rollup/rollup-android-arm64@4.50.1":
|
||||
version "4.50.1"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.50.1.tgz#6c708fae2c9755e994c42d56c34a94cb77020650"
|
||||
integrity sha512-PZlsJVcjHfcH53mOImyt3bc97Ep3FJDXRpk9sMdGX0qgLmY0EIWxCag6EigerGhLVuL8lDVYNnSo8qnTElO4xw==
|
||||
|
||||
"@rollup/rollup-darwin-arm64@4.44.0":
|
||||
version "4.44.0"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.44.0.tgz#60a51a61b22b1f4fdf97b4adf5f0f447f492759d"
|
||||
integrity sha512-VGF3wy0Eq1gcEIkSCr8Ke03CWT+Pm2yveKLaDvq51pPpZza3JX/ClxXOCmTYYq3us5MvEuNRTaeyFThCKRQhOA==
|
||||
"@rollup/rollup-darwin-arm64@4.50.1":
|
||||
version "4.50.1"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.50.1.tgz#85ccf92ab114e434c83037a175923a525635cbb4"
|
||||
integrity sha512-xc6i2AuWh++oGi4ylOFPmzJOEeAa2lJeGUGb4MudOtgfyyjr4UPNK+eEWTPLvmPJIY/pgw6ssFIox23SyrkkJw==
|
||||
|
||||
"@rollup/rollup-darwin-x64@4.44.0":
|
||||
version "4.44.0"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.44.0.tgz#bfe3059440f7032de11e749ece868cd7f232e609"
|
||||
integrity sha512-fBkyrDhwquRvrTxSGH/qqt3/T0w5Rg0L7ZIDypvBPc1/gzjJle6acCpZ36blwuwcKD/u6oCE/sRWlUAcxLWQbQ==
|
||||
"@rollup/rollup-darwin-x64@4.50.1":
|
||||
version "4.50.1"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.50.1.tgz#0af089f3d658d05573208dabb3a392b44d7f4630"
|
||||
integrity sha512-2ofU89lEpDYhdLAbRdeyz/kX3Y2lpYc6ShRnDjY35bZhd2ipuDMDi6ZTQ9NIag94K28nFMofdnKeHR7BT0CATw==
|
||||
|
||||
"@rollup/rollup-freebsd-arm64@4.44.0":
|
||||
version "4.44.0"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.44.0.tgz#d5d4c6cd3b8acb7493b76227d8b2b4a2d732a37b"
|
||||
integrity sha512-u5AZzdQJYJXByB8giQ+r4VyfZP+walV+xHWdaFx/1VxsOn6eWJhK2Vl2eElvDJFKQBo/hcYIBg/jaKS8ZmKeNQ==
|
||||
"@rollup/rollup-freebsd-arm64@4.50.1":
|
||||
version "4.50.1"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.50.1.tgz#46c22a16d18180e99686647543335567221caa9c"
|
||||
integrity sha512-wOsE6H2u6PxsHY/BeFHA4VGQN3KUJFZp7QJBmDYI983fgxq5Th8FDkVuERb2l9vDMs1D5XhOrhBrnqcEY6l8ZA==
|
||||
|
||||
"@rollup/rollup-freebsd-x64@4.44.0":
|
||||
version "4.44.0"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.44.0.tgz#cb4e1547b572cd0144c5fbd6c4a0edfed5fe6024"
|
||||
integrity sha512-qC0kS48c/s3EtdArkimctY7h3nHicQeEUdjJzYVJYR3ct3kWSafmn6jkNCA8InbUdge6PVx6keqjk5lVGJf99g==
|
||||
"@rollup/rollup-freebsd-x64@4.50.1":
|
||||
version "4.50.1"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.50.1.tgz#819ffef2f81891c266456952962a13110c8e28b5"
|
||||
integrity sha512-A/xeqaHTlKbQggxCqispFAcNjycpUEHP52mwMQZUNqDUJFFYtPHCXS1VAG29uMlDzIVr+i00tSFWFLivMcoIBQ==
|
||||
|
||||
"@rollup/rollup-linux-arm-gnueabihf@4.44.0":
|
||||
version "4.44.0"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.44.0.tgz#feb81bd086f6a469777f75bec07e1bdf93352e69"
|
||||
integrity sha512-x+e/Z9H0RAWckn4V2OZZl6EmV0L2diuX3QB0uM1r6BvhUIv6xBPL5mrAX2E3e8N8rEHVPwFfz/ETUbV4oW9+lQ==
|
||||
"@rollup/rollup-linux-arm-gnueabihf@4.50.1":
|
||||
version "4.50.1"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.50.1.tgz#7fe283c14793e607e653a3214b09f8973f08262a"
|
||||
integrity sha512-54v4okehwl5TaSIkpp97rAHGp7t3ghinRd/vyC1iXqXMfjYUTm7TfYmCzXDoHUPTTf36L8pr0E7YsD3CfB3ZDg==
|
||||
|
||||
"@rollup/rollup-linux-arm-musleabihf@4.44.0":
|
||||
version "4.44.0"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.44.0.tgz#68bff1c6620c155c9d8f5ee6a83c46eb50486f18"
|
||||
integrity sha512-1exwiBFf4PU/8HvI8s80icyCcnAIB86MCBdst51fwFmH5dyeoWVPVgmQPcKrMtBQ0W5pAs7jBCWuRXgEpRzSCg==
|
||||
"@rollup/rollup-linux-arm-musleabihf@4.50.1":
|
||||
version "4.50.1"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.50.1.tgz#066e92eb22ea30560414ec800a6d119ba0b435ac"
|
||||
integrity sha512-p/LaFyajPN/0PUHjv8TNyxLiA7RwmDoVY3flXHPSzqrGcIp/c2FjwPPP5++u87DGHtw+5kSH5bCJz0mvXngYxw==
|
||||
|
||||
"@rollup/rollup-linux-arm64-gnu@4.44.0":
|
||||
version "4.44.0"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.44.0.tgz#dbc5036a85e3ca3349887c8bdbebcfd011e460b0"
|
||||
integrity sha512-ZTR2mxBHb4tK4wGf9b8SYg0Y6KQPjGpR4UWwTFdnmjB4qRtoATZ5dWn3KsDwGa5Z2ZBOE7K52L36J9LueKBdOQ==
|
||||
"@rollup/rollup-linux-arm64-gnu@4.50.1":
|
||||
version "4.50.1"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.50.1.tgz#480d518ea99a8d97b2a174c46cd55164f138cc37"
|
||||
integrity sha512-2AbMhFFkTo6Ptna1zO7kAXXDLi7H9fGTbVaIq2AAYO7yzcAsuTNWPHhb2aTA6GPiP+JXh85Y8CiS54iZoj4opw==
|
||||
|
||||
"@rollup/rollup-linux-arm64-musl@4.44.0":
|
||||
version "4.44.0"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.44.0.tgz#72efc633aa0b93531bdfc69d70bcafa88e6152fc"
|
||||
integrity sha512-GFWfAhVhWGd4r6UxmnKRTBwP1qmModHtd5gkraeW2G490BpFOZkFtem8yuX2NyafIP/mGpRJgTJ2PwohQkUY/Q==
|
||||
"@rollup/rollup-linux-arm64-musl@4.50.1":
|
||||
version "4.50.1"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.50.1.tgz#ed7db3b8999b60dd20009ddf71c95f3af49423c8"
|
||||
integrity sha512-Cgef+5aZwuvesQNw9eX7g19FfKX5/pQRIyhoXLCiBOrWopjo7ycfB292TX9MDcDijiuIJlx1IzJz3IoCPfqs9w==
|
||||
|
||||
"@rollup/rollup-linux-loongarch64-gnu@4.44.0":
|
||||
version "4.44.0"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.44.0.tgz#9b6a49afde86c8f57ca11efdf8fd8d7c52048817"
|
||||
integrity sha512-xw+FTGcov/ejdusVOqKgMGW3c4+AgqrfvzWEVXcNP6zq2ue+lsYUgJ+5Rtn/OTJf7e2CbgTFvzLW2j0YAtj0Gg==
|
||||
"@rollup/rollup-linux-loongarch64-gnu@4.50.1":
|
||||
version "4.50.1"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.50.1.tgz#16a6927a35f5dbc505ff874a4e1459610c0c6f46"
|
||||
integrity sha512-RPhTwWMzpYYrHrJAS7CmpdtHNKtt2Ueo+BlLBjfZEhYBhK00OsEqM08/7f+eohiF6poe0YRDDd8nAvwtE/Y62Q==
|
||||
|
||||
"@rollup/rollup-linux-powerpc64le-gnu@4.44.0":
|
||||
version "4.44.0"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.44.0.tgz#93cb96073efab0cdbf419c8dfc44b5e2bd815139"
|
||||
integrity sha512-bKGibTr9IdF0zr21kMvkZT4K6NV+jjRnBoVMt2uNMG0BYWm3qOVmYnXKzx7UhwrviKnmK46IKMByMgvpdQlyJQ==
|
||||
"@rollup/rollup-linux-ppc64-gnu@4.50.1":
|
||||
version "4.50.1"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.50.1.tgz#a006700469be0041846c45b494c35754e6a04eea"
|
||||
integrity sha512-eSGMVQw9iekut62O7eBdbiccRguuDgiPMsw++BVUg+1K7WjZXHOg/YOT9SWMzPZA+w98G+Fa1VqJgHZOHHnY0Q==
|
||||
|
||||
"@rollup/rollup-linux-riscv64-gnu@4.44.0":
|
||||
version "4.44.0"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.44.0.tgz#028708f73c8130ae924e5c3755de50fe93687249"
|
||||
integrity sha512-vV3cL48U5kDaKZtXrti12YRa7TyxgKAIDoYdqSIOMOFBXqFj2XbChHAtXquEn2+n78ciFgr4KIqEbydEGPxXgA==
|
||||
"@rollup/rollup-linux-riscv64-gnu@4.50.1":
|
||||
version "4.50.1"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.50.1.tgz#0fcc45b2ec8a0e54218ca48849ea6d596f53649c"
|
||||
integrity sha512-S208ojx8a4ciIPrLgazF6AgdcNJzQE4+S9rsmOmDJkusvctii+ZvEuIC4v/xFqzbuP8yDjn73oBlNDgF6YGSXQ==
|
||||
|
||||
"@rollup/rollup-linux-riscv64-musl@4.44.0":
|
||||
version "4.44.0"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.44.0.tgz#878bfb158b2cf6671b7611fd58e5c80d9144ac6c"
|
||||
integrity sha512-TDKO8KlHJuvTEdfw5YYFBjhFts2TR0VpZsnLLSYmB7AaohJhM8ctDSdDnUGq77hUh4m/djRafw+9zQpkOanE2Q==
|
||||
"@rollup/rollup-linux-riscv64-musl@4.50.1":
|
||||
version "4.50.1"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.50.1.tgz#d6e617eec9fe6f5859ee13fad435a16c42b469f2"
|
||||
integrity sha512-3Ag8Ls1ggqkGUvSZWYcdgFwriy2lWo+0QlYgEFra/5JGtAd6C5Hw59oojx1DeqcA2Wds2ayRgvJ4qxVTzCHgzg==
|
||||
|
||||
"@rollup/rollup-linux-s390x-gnu@4.44.0":
|
||||
version "4.44.0"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.44.0.tgz#59b4ebb2129d34b7807ed8c462ff0baaefca9ad4"
|
||||
integrity sha512-8541GEyktXaw4lvnGp9m84KENcxInhAt6vPWJ9RodsB/iGjHoMB2Pp5MVBCiKIRxrxzJhGCxmNzdu+oDQ7kwRA==
|
||||
"@rollup/rollup-linux-s390x-gnu@4.50.1":
|
||||
version "4.50.1"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.50.1.tgz#b147760d63c6f35b4b18e6a25a2a760dd3ea0c05"
|
||||
integrity sha512-t9YrKfaxCYe7l7ldFERE1BRg/4TATxIg+YieHQ966jwvo7ddHJxPj9cNFWLAzhkVsbBvNA4qTbPVNsZKBO4NSg==
|
||||
|
||||
"@rollup/rollup-linux-x64-gnu@4.44.0":
|
||||
version "4.44.0"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.44.0.tgz#597d40f60d4b15bedbbacf2491a69c5b67a58e93"
|
||||
integrity sha512-iUVJc3c0o8l9Sa/qlDL2Z9UP92UZZW1+EmQ4xfjTc1akr0iUFZNfxrXJ/R1T90h/ILm9iXEY6+iPrmYB3pXKjw==
|
||||
"@rollup/rollup-linux-x64-gnu@4.50.1":
|
||||
version "4.50.1"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.50.1.tgz#fc0be1da374f85e7e85dccaf1ff12d7cfc9fbe3d"
|
||||
integrity sha512-MCgtFB2+SVNuQmmjHf+wfI4CMxy3Tk8XjA5Z//A0AKD7QXUYFMQcns91K6dEHBvZPCnhJSyDWLApk40Iq/H3tA==
|
||||
|
||||
"@rollup/rollup-linux-x64-musl@4.44.0":
|
||||
version "4.44.0"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.44.0.tgz#0a062d6fee35ec4fbb607b2a9d933a9372ccf63a"
|
||||
integrity sha512-PQUobbhLTQT5yz/SPg116VJBgz+XOtXt8D1ck+sfJJhuEsMj2jSej5yTdp8CvWBSceu+WW+ibVL6dm0ptG5fcA==
|
||||
"@rollup/rollup-linux-x64-musl@4.50.1":
|
||||
version "4.50.1"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.50.1.tgz#54c79932e0f9a3c992b034c82325be3bcde0d067"
|
||||
integrity sha512-nEvqG+0jeRmqaUMuwzlfMKwcIVffy/9KGbAGyoa26iu6eSngAYQ512bMXuqqPrlTyfqdlB9FVINs93j534UJrg==
|
||||
|
||||
"@rollup/rollup-win32-arm64-msvc@4.44.0":
|
||||
version "4.44.0"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.44.0.tgz#41ffab489857987c75385b0fc8cccf97f7e69d0a"
|
||||
integrity sha512-M0CpcHf8TWn+4oTxJfh7LQuTuaYeXGbk0eageVjQCKzYLsajWS/lFC94qlRqOlyC2KvRT90ZrfXULYmukeIy7w==
|
||||
"@rollup/rollup-openharmony-arm64@4.50.1":
|
||||
version "4.50.1"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.50.1.tgz#fc48e74d413623ac02c1d521bec3e5e784488fdc"
|
||||
integrity sha512-RDsLm+phmT3MJd9SNxA9MNuEAO/J2fhW8GXk62G/B4G7sLVumNFbRwDL6v5NrESb48k+QMqdGbHgEtfU0LCpbA==
|
||||
|
||||
"@rollup/rollup-win32-ia32-msvc@4.44.0":
|
||||
version "4.44.0"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.44.0.tgz#d9fb61d98eedfa52720b6ed9f31442b3ef4b839f"
|
||||
integrity sha512-3XJ0NQtMAXTWFW8FqZKcw3gOQwBtVWP/u8TpHP3CRPXD7Pd6s8lLdH3sHWh8vqKCyyiI8xW5ltJScQmBU9j7WA==
|
||||
"@rollup/rollup-win32-arm64-msvc@4.50.1":
|
||||
version "4.50.1"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.50.1.tgz#8ce3d1181644406362cf1e62c90e88ab083e02bb"
|
||||
integrity sha512-hpZB/TImk2FlAFAIsoElM3tLzq57uxnGYwplg6WDyAxbYczSi8O2eQ+H2Lx74504rwKtZ3N2g4bCUkiamzS6TQ==
|
||||
|
||||
"@rollup/rollup-win32-x64-msvc@4.44.0":
|
||||
version "4.44.0"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.44.0.tgz#a36e79b6ccece1533f777a1bca1f89c13f0c5f62"
|
||||
integrity sha512-Q2Mgwt+D8hd5FIPUuPDsvPR7Bguza6yTkJxspDGkZj7tBRn2y4KSWYuIXpftFSjBra76TbKerCV7rgFPQrn+wQ==
|
||||
"@rollup/rollup-win32-ia32-msvc@4.50.1":
|
||||
version "4.50.1"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.50.1.tgz#dd2dfc896eac4b2689d55f01c6d51c249263f805"
|
||||
integrity sha512-SXjv8JlbzKM0fTJidX4eVsH+Wmnp0/WcD8gJxIZyR6Gay5Qcsmdbi9zVtnbkGPG8v2vMR1AD06lGWy5FLMcG7A==
|
||||
|
||||
"@rollup/rollup-win32-x64-msvc@4.50.1":
|
||||
version "4.50.1"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.50.1.tgz#13f758c97b9fbbac56b6928547a3ff384e7cfb3e"
|
||||
integrity sha512-StxAO/8ts62KZVRAm4JZYq9+NqNsV7RvimNK+YM7ry//zebEH6meuugqW/P5OFUCjyQgui+9fUxT6d5NShvMvA==
|
||||
|
||||
"@surma/rollup-plugin-off-main-thread@^2.2.3":
|
||||
version "2.2.3"
|
||||
@@ -1257,24 +1262,24 @@
|
||||
dependencies:
|
||||
"@rolldown/pluginutils" "1.0.0-beta.19"
|
||||
|
||||
"@volar/language-core@2.4.14", "@volar/language-core@~2.4.11":
|
||||
version "2.4.14"
|
||||
resolved "https://registry.yarnpkg.com/@volar/language-core/-/language-core-2.4.14.tgz#dac7573014d4f3bafb186cb16888ffea5698be71"
|
||||
integrity sha512-X6beusV0DvuVseaOEy7GoagS4rYHgDHnTrdOj5jeUb49fW5ceQyP9Ej5rBhqgz2wJggl+2fDbbojq1XKaxDi6w==
|
||||
"@volar/language-core@2.4.23":
|
||||
version "2.4.23"
|
||||
resolved "https://registry.yarnpkg.com/@volar/language-core/-/language-core-2.4.23.tgz#deb6dbc5fdbafa9bb7ba691fc59cb196cdb856d3"
|
||||
integrity sha512-hEEd5ET/oSmBC6pi1j6NaNYRWoAiDhINbT8rmwtINugR39loROSlufGdYMF9TaKGfz+ViGs1Idi3mAhnuPcoGQ==
|
||||
dependencies:
|
||||
"@volar/source-map" "2.4.14"
|
||||
"@volar/source-map" "2.4.23"
|
||||
|
||||
"@volar/source-map@2.4.14":
|
||||
version "2.4.14"
|
||||
resolved "https://registry.yarnpkg.com/@volar/source-map/-/source-map-2.4.14.tgz#cdcecd533c2e767449b2414cc22327d2bda7ef95"
|
||||
integrity sha512-5TeKKMh7Sfxo8021cJfmBzcjfY1SsXsPMMjMvjY7ivesdnybqqS+GxGAoXHAOUawQTwtdUxgP65Im+dEmvWtYQ==
|
||||
"@volar/source-map@2.4.23":
|
||||
version "2.4.23"
|
||||
resolved "https://registry.yarnpkg.com/@volar/source-map/-/source-map-2.4.23.tgz#d476e11a3a669d89858a5eb38b02342be39b0e44"
|
||||
integrity sha512-Z1Uc8IB57Lm6k7q6KIDu/p+JWtf3xsXJqAX/5r18hYOTpJyBn0KXUR8oTJ4WFYOcDzWC9n3IflGgHowx6U6z9Q==
|
||||
|
||||
"@volar/typescript@~2.4.11":
|
||||
version "2.4.14"
|
||||
resolved "https://registry.yarnpkg.com/@volar/typescript/-/typescript-2.4.14.tgz#b99a1025dd6a8b751e96627ebcb0739ceed0e5f1"
|
||||
integrity sha512-p8Z6f/bZM3/HyCdRNFZOEEzts51uV8WHeN8Tnfnm2EBv6FDB2TQLzfVx7aJvnl8ofKAOnS64B2O8bImBFaauRw==
|
||||
"@volar/typescript@2.4.23":
|
||||
version "2.4.23"
|
||||
resolved "https://registry.yarnpkg.com/@volar/typescript/-/typescript-2.4.23.tgz#b9b114ea01ad0ad977139edda0239fdafdb21ad7"
|
||||
integrity sha512-lAB5zJghWxVPqfcStmAP1ZqQacMpe90UrP5RJ3arDyrhy4aCUQqmxPPLB2PWDKugvylmO41ljK7vZ+t6INMTag==
|
||||
dependencies:
|
||||
"@volar/language-core" "2.4.14"
|
||||
"@volar/language-core" "2.4.23"
|
||||
path-browserify "^1.0.1"
|
||||
vscode-uri "^3.0.8"
|
||||
|
||||
@@ -1360,19 +1365,19 @@
|
||||
dependencies:
|
||||
rfdc "^1.4.1"
|
||||
|
||||
"@vue/language-core@2.2.10":
|
||||
version "2.2.10"
|
||||
resolved "https://registry.yarnpkg.com/@vue/language-core/-/language-core-2.2.10.tgz#5ae1e71a4e16dd59d1e4bac167f4b9c8c04d9f17"
|
||||
integrity sha512-+yNoYx6XIKuAO8Mqh1vGytu8jkFEOH5C8iOv3i8Z/65A7x9iAOXA97Q+PqZ3nlm2lxf5rOJuIGI/wDtx/riNYw==
|
||||
"@vue/language-core@3.0.6":
|
||||
version "3.0.6"
|
||||
resolved "https://registry.yarnpkg.com/@vue/language-core/-/language-core-3.0.6.tgz#5e9d2f58f3a91465c5d86e460f0239f9c6e8300d"
|
||||
integrity sha512-e2RRzYWm+qGm8apUHW1wA5RQxzNhkqbbKdbKhiDUcmMrNAZGyM8aTiL3UrTqkaFI5s7wJRGGrp4u3jgusuBp2A==
|
||||
dependencies:
|
||||
"@volar/language-core" "~2.4.11"
|
||||
"@volar/language-core" "2.4.23"
|
||||
"@vue/compiler-dom" "^3.5.0"
|
||||
"@vue/compiler-vue2" "^2.7.16"
|
||||
"@vue/shared" "^3.5.0"
|
||||
alien-signals "^1.0.3"
|
||||
minimatch "^9.0.3"
|
||||
alien-signals "^2.0.5"
|
||||
muggle-string "^0.4.1"
|
||||
path-browserify "^1.0.1"
|
||||
picomatch "^4.0.2"
|
||||
|
||||
"@vue/reactivity@3.5.17":
|
||||
version "3.5.17"
|
||||
@@ -1475,10 +1480,10 @@ ajv@^8.6.0:
|
||||
json-schema-traverse "^1.0.0"
|
||||
require-from-string "^2.0.2"
|
||||
|
||||
alien-signals@^1.0.3:
|
||||
version "1.0.13"
|
||||
resolved "https://registry.yarnpkg.com/alien-signals/-/alien-signals-1.0.13.tgz#8d6db73462f742ee6b89671fbd8c37d0b1727a7e"
|
||||
integrity sha512-OGj9yyTnJEttvzhTUWuscOvtqxq5vrhF7vL9oS0xJ2mK0ItPYP1/y+vCFebfxoEyAz0++1AIwJ5CMr+Fk3nDmg==
|
||||
alien-signals@^2.0.5:
|
||||
version "2.0.7"
|
||||
resolved "https://registry.yarnpkg.com/alien-signals/-/alien-signals-2.0.7.tgz#8c695e01878081046f1486e7e332380db35fb7e6"
|
||||
integrity sha512-wE7y3jmYeb0+h6mr5BOovuqhFv22O/MV9j5p0ndJsa7z1zJNPGQ4ph5pQk/kTTCWRC3xsA4SmtwmkzQO+7NCNg==
|
||||
|
||||
ansi-styles@^4.1.0:
|
||||
version "4.3.0"
|
||||
@@ -1977,10 +1982,10 @@ fast-uri@^3.0.1:
|
||||
resolved "https://registry.yarnpkg.com/fast-uri/-/fast-uri-3.0.6.tgz#88f130b77cfaea2378d56bf970dea21257a68748"
|
||||
integrity sha512-Atfo14OibSv5wAp4VWNsFYE1AchQRTv9cBGWET4pZWHzYshFSS9NQI6I57rdKn9croWVMbYFbLhJ+yJvmZIIHw==
|
||||
|
||||
fdir@^6.4.4:
|
||||
version "6.4.6"
|
||||
resolved "https://registry.yarnpkg.com/fdir/-/fdir-6.4.6.tgz#2b268c0232697063111bbf3f64810a2a741ba281"
|
||||
integrity sha512-hiFoqpyZcfNm1yc4u8oWCf9A2c4D3QjCrks3zmoVKVxpQRzmPNar1hUJcBG2RQHvEVGDN+Jm81ZheVLAQMK6+w==
|
||||
fdir@^6.5.0:
|
||||
version "6.5.0"
|
||||
resolved "https://registry.yarnpkg.com/fdir/-/fdir-6.5.0.tgz#ed2ab967a331ade62f18d077dae192684d50d350"
|
||||
integrity sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==
|
||||
|
||||
filelist@^1.0.4:
|
||||
version "1.0.4"
|
||||
@@ -2583,13 +2588,6 @@ minimatch@^5.0.1:
|
||||
dependencies:
|
||||
brace-expansion "^2.0.1"
|
||||
|
||||
minimatch@^9.0.3:
|
||||
version "9.0.5"
|
||||
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.5.tgz#d74f9dd6b57d83d8e98cfb82133b03978bc929e5"
|
||||
integrity sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==
|
||||
dependencies:
|
||||
brace-expansion "^2.0.1"
|
||||
|
||||
mitt@^3.0.1:
|
||||
version "3.0.1"
|
||||
resolved "https://registry.yarnpkg.com/mitt/-/mitt-3.0.1.tgz#ea36cf0cc30403601ae074c8f77b7092cdab36d1"
|
||||
@@ -2695,10 +2693,10 @@ picomatch@^2.2.2:
|
||||
resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42"
|
||||
integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==
|
||||
|
||||
picomatch@^4.0.2:
|
||||
version "4.0.2"
|
||||
resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-4.0.2.tgz#77c742931e8f3b8820946c76cd0c1f13730d1dab"
|
||||
integrity sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==
|
||||
picomatch@^4.0.2, picomatch@^4.0.3:
|
||||
version "4.0.3"
|
||||
resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-4.0.3.tgz#796c76136d1eead715db1e7bad785dedd695a042"
|
||||
integrity sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==
|
||||
|
||||
pinia@^3.0.2:
|
||||
version "3.0.3"
|
||||
@@ -2712,7 +2710,7 @@ possible-typed-array-names@^1.0.0:
|
||||
resolved "https://registry.yarnpkg.com/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz#93e3582bc0e5426586d9d07b79ee40fc841de4ae"
|
||||
integrity sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==
|
||||
|
||||
postcss@^8.5.3, postcss@^8.5.6:
|
||||
postcss@^8.5.6:
|
||||
version "8.5.6"
|
||||
resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.5.6.tgz#2825006615a619b4f62a9e7426cc120b349a8f3c"
|
||||
integrity sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==
|
||||
@@ -2831,33 +2829,34 @@ rollup@^2.43.1:
|
||||
optionalDependencies:
|
||||
fsevents "~2.3.2"
|
||||
|
||||
rollup@^4.34.9:
|
||||
version "4.44.0"
|
||||
resolved "https://registry.yarnpkg.com/rollup/-/rollup-4.44.0.tgz#0e10b98339b306edad1e612f1e5590a79aef521c"
|
||||
integrity sha512-qHcdEzLCiktQIfwBq420pn2dP+30uzqYxv9ETm91wdt2R9AFcWfjNAmje4NWlnCIQ5RMTzVf0ZyisOKqHR6RwA==
|
||||
rollup@^4.43.0:
|
||||
version "4.50.1"
|
||||
resolved "https://registry.yarnpkg.com/rollup/-/rollup-4.50.1.tgz#6f0717c34aacc65cc727eeaaaccc2afc4e4485fd"
|
||||
integrity sha512-78E9voJHwnXQMiQdiqswVLZwJIzdBKJ1GdI5Zx6XwoFKUIk09/sSrr+05QFzvYb8q6Y9pPV45zzDuYa3907TZA==
|
||||
dependencies:
|
||||
"@types/estree" "1.0.8"
|
||||
optionalDependencies:
|
||||
"@rollup/rollup-android-arm-eabi" "4.44.0"
|
||||
"@rollup/rollup-android-arm64" "4.44.0"
|
||||
"@rollup/rollup-darwin-arm64" "4.44.0"
|
||||
"@rollup/rollup-darwin-x64" "4.44.0"
|
||||
"@rollup/rollup-freebsd-arm64" "4.44.0"
|
||||
"@rollup/rollup-freebsd-x64" "4.44.0"
|
||||
"@rollup/rollup-linux-arm-gnueabihf" "4.44.0"
|
||||
"@rollup/rollup-linux-arm-musleabihf" "4.44.0"
|
||||
"@rollup/rollup-linux-arm64-gnu" "4.44.0"
|
||||
"@rollup/rollup-linux-arm64-musl" "4.44.0"
|
||||
"@rollup/rollup-linux-loongarch64-gnu" "4.44.0"
|
||||
"@rollup/rollup-linux-powerpc64le-gnu" "4.44.0"
|
||||
"@rollup/rollup-linux-riscv64-gnu" "4.44.0"
|
||||
"@rollup/rollup-linux-riscv64-musl" "4.44.0"
|
||||
"@rollup/rollup-linux-s390x-gnu" "4.44.0"
|
||||
"@rollup/rollup-linux-x64-gnu" "4.44.0"
|
||||
"@rollup/rollup-linux-x64-musl" "4.44.0"
|
||||
"@rollup/rollup-win32-arm64-msvc" "4.44.0"
|
||||
"@rollup/rollup-win32-ia32-msvc" "4.44.0"
|
||||
"@rollup/rollup-win32-x64-msvc" "4.44.0"
|
||||
"@rollup/rollup-android-arm-eabi" "4.50.1"
|
||||
"@rollup/rollup-android-arm64" "4.50.1"
|
||||
"@rollup/rollup-darwin-arm64" "4.50.1"
|
||||
"@rollup/rollup-darwin-x64" "4.50.1"
|
||||
"@rollup/rollup-freebsd-arm64" "4.50.1"
|
||||
"@rollup/rollup-freebsd-x64" "4.50.1"
|
||||
"@rollup/rollup-linux-arm-gnueabihf" "4.50.1"
|
||||
"@rollup/rollup-linux-arm-musleabihf" "4.50.1"
|
||||
"@rollup/rollup-linux-arm64-gnu" "4.50.1"
|
||||
"@rollup/rollup-linux-arm64-musl" "4.50.1"
|
||||
"@rollup/rollup-linux-loongarch64-gnu" "4.50.1"
|
||||
"@rollup/rollup-linux-ppc64-gnu" "4.50.1"
|
||||
"@rollup/rollup-linux-riscv64-gnu" "4.50.1"
|
||||
"@rollup/rollup-linux-riscv64-musl" "4.50.1"
|
||||
"@rollup/rollup-linux-s390x-gnu" "4.50.1"
|
||||
"@rollup/rollup-linux-x64-gnu" "4.50.1"
|
||||
"@rollup/rollup-linux-x64-musl" "4.50.1"
|
||||
"@rollup/rollup-openharmony-arm64" "4.50.1"
|
||||
"@rollup/rollup-win32-arm64-msvc" "4.50.1"
|
||||
"@rollup/rollup-win32-ia32-msvc" "4.50.1"
|
||||
"@rollup/rollup-win32-x64-msvc" "4.50.1"
|
||||
fsevents "~2.3.2"
|
||||
|
||||
rrweb-cssom@^0.8.0:
|
||||
@@ -3160,13 +3159,13 @@ terser@^5.17.4:
|
||||
commander "^2.20.0"
|
||||
source-map-support "~0.5.20"
|
||||
|
||||
tinyglobby@^0.2.10, tinyglobby@^0.2.13:
|
||||
version "0.2.14"
|
||||
resolved "https://registry.yarnpkg.com/tinyglobby/-/tinyglobby-0.2.14.tgz#5280b0cf3f972b050e74ae88406c0a6a58f4079d"
|
||||
integrity sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ==
|
||||
tinyglobby@^0.2.10, tinyglobby@^0.2.15:
|
||||
version "0.2.15"
|
||||
resolved "https://registry.yarnpkg.com/tinyglobby/-/tinyglobby-0.2.15.tgz#e228dd1e638cea993d2fdb4fcd2d4602a79951c2"
|
||||
integrity sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==
|
||||
dependencies:
|
||||
fdir "^6.4.4"
|
||||
picomatch "^4.0.2"
|
||||
fdir "^6.5.0"
|
||||
picomatch "^4.0.3"
|
||||
|
||||
tldts-core@^6.1.86:
|
||||
version "6.1.86"
|
||||
@@ -3324,10 +3323,10 @@ update-browserslist-db@^1.1.3:
|
||||
escalade "^3.2.0"
|
||||
picocolors "^1.1.1"
|
||||
|
||||
vite-plugin-pwa@^1.0.2:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/vite-plugin-pwa/-/vite-plugin-pwa-1.0.2.tgz#ad70181256633c56ce7aa85c66377d916b9e8296"
|
||||
integrity sha512-O3UwjsCnoDclgJANoOgzzqW7SFgwXE/th2OmUP/ILxHKwzWxxKDBu+B/Xa9Cv4IgSVSnj2HgRVIJ7F15+vQFkA==
|
||||
vite-plugin-pwa@^1.0.3:
|
||||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/vite-plugin-pwa/-/vite-plugin-pwa-1.0.3.tgz#607a7fda7170920280d85b1d2dbac293c3d2efdf"
|
||||
integrity sha512-/OpqIpUldALGxcsEnv/ekQiQ5xHkQ53wcoN5ewX4jiIDNGs3W+eNcI1WYZeyOLmzoEjg09D7aX0O89YGjen1aw==
|
||||
dependencies:
|
||||
debug "^4.3.6"
|
||||
pretty-bytes "^6.1.1"
|
||||
@@ -3344,17 +3343,17 @@ vite-plugin-vuetify@^2.1.1:
|
||||
debug "^4.3.3"
|
||||
upath "^2.0.1"
|
||||
|
||||
vite@6.3.5:
|
||||
version "6.3.5"
|
||||
resolved "https://registry.yarnpkg.com/vite/-/vite-6.3.5.tgz#fec73879013c9c0128c8d284504c6d19410d12a3"
|
||||
integrity sha512-cZn6NDFE7wdTpINgs++ZJ4N49W2vRp8LCKrn3Ob1kYNtOo21vfDoaV5GzBfLU4MovSAB8uNRm4jgzVQZ+mBzPQ==
|
||||
vite@7.1.5:
|
||||
version "7.1.5"
|
||||
resolved "https://registry.yarnpkg.com/vite/-/vite-7.1.5.tgz#4dbcb48c6313116689be540466fc80faa377be38"
|
||||
integrity sha512-4cKBO9wR75r0BeIWWWId9XK9Lj6La5X846Zw9dFfzMRw38IlTk2iCcUt6hsyiDRcPidc55ZParFYDXi0nXOeLQ==
|
||||
dependencies:
|
||||
esbuild "^0.25.0"
|
||||
fdir "^6.4.4"
|
||||
picomatch "^4.0.2"
|
||||
postcss "^8.5.3"
|
||||
rollup "^4.34.9"
|
||||
tinyglobby "^0.2.13"
|
||||
fdir "^6.5.0"
|
||||
picomatch "^4.0.3"
|
||||
postcss "^8.5.6"
|
||||
rollup "^4.43.0"
|
||||
tinyglobby "^0.2.15"
|
||||
optionalDependencies:
|
||||
fsevents "~2.3.3"
|
||||
|
||||
@@ -3370,13 +3369,13 @@ vue-draggable-plus@^0.6.0:
|
||||
dependencies:
|
||||
"@types/sortablejs" "^1.15.8"
|
||||
|
||||
vue-i18n@^11.1.10:
|
||||
version "11.1.10"
|
||||
resolved "https://registry.yarnpkg.com/vue-i18n/-/vue-i18n-11.1.10.tgz#04578ea4213f96c37939a08f516a648a6d0b84a1"
|
||||
integrity sha512-C+IwnSg8QDSOAox0gdFYP5tsKLx5jNWxiawNoiNB/Tw4CReXmM1VJMXbduhbrEzAFLhreqzfDocuSVjGbxQrag==
|
||||
vue-i18n@^11.1.11:
|
||||
version "11.1.11"
|
||||
resolved "https://registry.yarnpkg.com/vue-i18n/-/vue-i18n-11.1.11.tgz#b38ed214896540cf7a68932dfa565d9d4fbbffac"
|
||||
integrity sha512-LvyteQoXeQiuILbzqv13LbyBna/TEv2Ha+4ZWK2AwGHUzZ8+IBaZS0TJkCgn5izSPLcgZwXy9yyTrewCb2u/MA==
|
||||
dependencies:
|
||||
"@intlify/core-base" "11.1.10"
|
||||
"@intlify/shared" "11.1.10"
|
||||
"@intlify/core-base" "11.1.11"
|
||||
"@intlify/shared" "11.1.11"
|
||||
"@vue/devtools-api" "^6.5.0"
|
||||
|
||||
vue-router@^4.5.0:
|
||||
@@ -3393,13 +3392,13 @@ vue-simple-calendar@7.1.0:
|
||||
dependencies:
|
||||
vue "^3.4.15"
|
||||
|
||||
vue-tsc@^2.2.8:
|
||||
version "2.2.10"
|
||||
resolved "https://registry.yarnpkg.com/vue-tsc/-/vue-tsc-2.2.10.tgz#7b51a666cb90788884efd0caedc69fc1fc9c5b78"
|
||||
integrity sha512-jWZ1xSaNbabEV3whpIDMbjVSVawjAyW+x1n3JeGQo7S0uv2n9F/JMgWW90tGWNFRKya4YwKMZgCtr0vRAM7DeQ==
|
||||
vue-tsc@^3.0.6:
|
||||
version "3.0.6"
|
||||
resolved "https://registry.yarnpkg.com/vue-tsc/-/vue-tsc-3.0.6.tgz#09376812d2f1fab64e3592ab93281dc62e6d2754"
|
||||
integrity sha512-Tbs8Whd43R2e2nxez4WXPvvdjGbW24rOSgRhLOHXzWiT4pcP4G7KeWh0YCn18rF4bVwv7tggLLZ6MJnO6jXPBg==
|
||||
dependencies:
|
||||
"@volar/typescript" "~2.4.11"
|
||||
"@vue/language-core" "2.2.10"
|
||||
"@volar/typescript" "2.4.23"
|
||||
"@vue/language-core" "3.0.6"
|
||||
|
||||
vue@^3.4.15, vue@^3.5.13:
|
||||
version "3.5.17"
|
||||
@@ -3419,10 +3418,10 @@ vuedraggable@^4.1.0:
|
||||
dependencies:
|
||||
sortablejs "1.14.0"
|
||||
|
||||
vuetify@^3.9.3:
|
||||
version "3.9.3"
|
||||
resolved "https://registry.yarnpkg.com/vuetify/-/vuetify-3.9.3.tgz#b97dab322132e82fb247c469f674d5610bd19396"
|
||||
integrity sha512-0eruHdmRoAMBo/08RLDkTdtdu1vfkx+/PurUIDW2tz/k2GCp51e7KwgCn4uVyzH88KRgf2PKiz5UI5f93Xn05w==
|
||||
vuetify@^3.9.7:
|
||||
version "3.9.7"
|
||||
resolved "https://registry.yarnpkg.com/vuetify/-/vuetify-3.9.7.tgz#aea996f35111f25dd7e31ab956fbb40911841c24"
|
||||
integrity sha512-Ib8PB3ItcguCol8f0DXLpoGyy7FvoOYW23SEWqXX+in1CSItJZHxUXXGSus94m5JWqYqQrFiwCykbHm7UWPi4Q==
|
||||
|
||||
w3c-xmlserializer@^5.0.0:
|
||||
version "5.0.0"
|
||||
|
||||
Reference in New Issue
Block a user