mirror of
https://github.com/TandoorRecipes/recipes.git
synced 2025-12-27 20:18:58 -05:00
Compare commits
26 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c78b7a6928 | ||
|
|
7a2ccc075c | ||
|
|
237054c23e | ||
|
|
ac1d641bd5 | ||
|
|
3545b6e98a | ||
|
|
d3a56e00ea | ||
|
|
e9f8578c25 | ||
|
|
dccfc436be | ||
|
|
1e85c8587b | ||
|
|
b8f92ab054 | ||
|
|
766ed31f8e | ||
|
|
cad78e115d | ||
|
|
b599c4f6a9 | ||
|
|
439539f56d | ||
|
|
237bcb92c9 | ||
|
|
ce02a23dbb | ||
|
|
8e81512735 | ||
|
|
c69f0394a8 | ||
|
|
d7ca9e05de | ||
|
|
64534ff810 | ||
|
|
d0164a6c28 | ||
|
|
0f898ddf4a | ||
|
|
e903382034 | ||
|
|
0d225450da | ||
|
|
c077a64484 | ||
|
|
6c16094b42 |
8
.github/workflows/build-docker.yml
vendored
8
.github/workflows/build-docker.yml
vendored
@@ -17,15 +17,9 @@ jobs:
|
||||
# Standard build config
|
||||
- name: Standard
|
||||
dockerfile: Dockerfile
|
||||
platforms: linux/amd64,linux/arm64
|
||||
platforms: linux/amd64,linux/arm64,linux/arm/v7
|
||||
suffix: ""
|
||||
continue-on-error: false
|
||||
# Raspi build config
|
||||
- name: Raspi
|
||||
dockerfile: Dockerfile-raspi
|
||||
platforms: linux/arm/v7
|
||||
suffix: "-raspi"
|
||||
continue-on-error: true
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
FROM python:3.10-alpine3.15
|
||||
FROM python:3.10-alpine3.18
|
||||
|
||||
#Install all dependencies.
|
||||
RUN apk add --no-cache postgresql-libs postgresql-client gettext zlib libjpeg libwebp libxml2-dev libxslt-dev py-cryptography openldap
|
||||
RUN apk add --no-cache postgresql-libs postgresql-client gettext zlib libjpeg libwebp libxml2-dev libxslt-dev openldap
|
||||
|
||||
#Print all logs without buffering it.
|
||||
ENV PYTHONUNBUFFERED 1
|
||||
@@ -15,6 +15,10 @@ WORKDIR /opt/recipes
|
||||
|
||||
COPY requirements.txt ./
|
||||
|
||||
RUN \
|
||||
if [ `apk --print-arch` = "armv7" ]; then \
|
||||
printf "[global]\nextra-index-url=https://www.piwheels.org/simple\n" > /etc/pip.conf ; \
|
||||
fi
|
||||
RUN apk add --no-cache --virtual .build-deps gcc musl-dev postgresql-dev zlib-dev jpeg-dev libwebp-dev openssl-dev libffi-dev cargo openldap-dev python3-dev git && \
|
||||
echo -n "INPUT ( libldap.so )" > /usr/lib/libldap_r.so && \
|
||||
python -m venv venv && \
|
||||
|
||||
@@ -1,33 +0,0 @@
|
||||
# builds of cryptography for raspberry pi (or better arm v7) fail for some
|
||||
FROM python:3.9-alpine3.15
|
||||
|
||||
#Install all dependencies.
|
||||
RUN apk add --no-cache postgresql-libs postgresql-client gettext zlib libjpeg libwebp libxml2-dev libxslt-dev py-cryptography openldap gcompat
|
||||
|
||||
#Print all logs without buffering it.
|
||||
ENV PYTHONUNBUFFERED 1
|
||||
|
||||
#This port will be used by gunicorn.
|
||||
EXPOSE 8080
|
||||
|
||||
#Create app dir and install requirements.
|
||||
RUN mkdir /opt/recipes
|
||||
WORKDIR /opt/recipes
|
||||
|
||||
COPY requirements.txt ./
|
||||
RUN \
|
||||
if [ `apk --print-arch` = "armv7" ]; then \
|
||||
printf "[global]\nextra-index-url=https://www.piwheels.org/simple\n" > /etc/pip.conf ; \
|
||||
fi
|
||||
RUN apk add --no-cache --virtual .build-deps gcc musl-dev zlib-dev jpeg-dev libwebp-dev python3-dev git && \
|
||||
echo -n "INPUT ( libldap.so )" > /usr/lib/libldap_r.so && \
|
||||
python -m venv venv && \
|
||||
/opt/recipes/venv/bin/python -m pip install --upgrade pip && \
|
||||
venv/bin/pip install wheel==0.37.1 && \
|
||||
venv/bin/pip install -r requirements.txt --no-cache-dir --no-binary=Pillow && \
|
||||
apk --purge del .build-deps
|
||||
|
||||
#Copy project and execute it.
|
||||
COPY . ./
|
||||
RUN chmod +x boot.sh
|
||||
ENTRYPOINT ["/opt/recipes/boot.sh"]
|
||||
@@ -39,6 +39,8 @@ def delete_space_action(modeladmin, request, queryset):
|
||||
class SpaceAdmin(admin.ModelAdmin):
|
||||
list_display = ('name', 'created_by', 'max_recipes', 'max_users', 'max_file_storage_mb', 'allow_sharing')
|
||||
search_fields = ('name', 'created_by__username')
|
||||
autocomplete_fields = ('created_by',)
|
||||
filter_horizontal = ('food_inherit',)
|
||||
list_filter = ('max_recipes', 'max_users', 'max_file_storage_mb', 'allow_sharing')
|
||||
date_hierarchy = 'created_at'
|
||||
actions = [delete_space_action]
|
||||
@@ -50,6 +52,8 @@ admin.site.register(Space, SpaceAdmin)
|
||||
class UserSpaceAdmin(admin.ModelAdmin):
|
||||
list_display = ('user', 'space',)
|
||||
search_fields = ('user__username', 'space__name',)
|
||||
filter_horizontal = ('groups',)
|
||||
autocomplete_fields = ('user', 'space',)
|
||||
|
||||
|
||||
admin.site.register(UserSpace, UserSpaceAdmin)
|
||||
@@ -60,6 +64,7 @@ class UserPreferenceAdmin(admin.ModelAdmin):
|
||||
search_fields = ('user__username',)
|
||||
list_filter = ('theme', 'nav_color', 'default_page',)
|
||||
date_hierarchy = 'created_at'
|
||||
filter_horizontal = ('plan_share', 'shopping_share',)
|
||||
|
||||
@staticmethod
|
||||
def name(obj):
|
||||
|
||||
@@ -434,3 +434,10 @@ def switch_user_active_space(user, space):
|
||||
return us
|
||||
except ObjectDoesNotExist:
|
||||
return None
|
||||
|
||||
|
||||
class IsReadOnlyDRF(permissions.BasePermission):
|
||||
message = 'You cannot interact with this object as it is not owned by you!'
|
||||
|
||||
def has_permission(self, request, view):
|
||||
return request.method in SAFE_METHODS
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
# Generated by Django 4.1.9 on 2023-06-30 20:34
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('cookbook', '0194_alter_food_properties_food_amount'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='invitelink',
|
||||
name='internal_note',
|
||||
field=models.TextField(blank=True, null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='userspace',
|
||||
name='internal_note',
|
||||
field=models.TextField(blank=True, null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='userspace',
|
||||
name='invite_link',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='cookbook.invitelink'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='userpreference',
|
||||
name='theme',
|
||||
field=models.CharField(choices=[('TANDOOR', 'Tandoor'), ('BOOTSTRAP', 'Bootstrap'), ('DARKLY', 'Darkly'), ('FLATLY', 'Flatly'), ('SUPERHERO', 'Superhero'), ('TANDOOR_DARK', 'Tandoor Dark (INCOMPLETE)')], default='TANDOOR', max_length=128),
|
||||
),
|
||||
]
|
||||
@@ -331,6 +331,7 @@ class UserPreference(models.Model, PermissionModelMixin):
|
||||
FLATLY = 'FLATLY'
|
||||
SUPERHERO = 'SUPERHERO'
|
||||
TANDOOR = 'TANDOOR'
|
||||
TANDOOR_DARK = 'TANDOOR_DARK'
|
||||
|
||||
THEMES = (
|
||||
(TANDOOR, 'Tandoor'),
|
||||
@@ -338,6 +339,7 @@ class UserPreference(models.Model, PermissionModelMixin):
|
||||
(DARKLY, 'Darkly'),
|
||||
(FLATLY, 'Flatly'),
|
||||
(SUPERHERO, 'Superhero'),
|
||||
(TANDOOR_DARK, 'Tandoor Dark (INCOMPLETE)'),
|
||||
)
|
||||
|
||||
# Nav colors
|
||||
@@ -413,6 +415,9 @@ class UserSpace(models.Model, PermissionModelMixin):
|
||||
# that having more than one active space should just break certain parts of the application and not leak any data
|
||||
active = models.BooleanField(default=False)
|
||||
|
||||
invite_link = models.ForeignKey("InviteLink", on_delete=models.PROTECT, null=True, blank=True)
|
||||
internal_note = models.TextField(blank=True, null=True)
|
||||
|
||||
created_at = models.DateTimeField(auto_now_add=True)
|
||||
updated_at = models.DateTimeField(auto_now=True)
|
||||
|
||||
@@ -717,25 +722,6 @@ class Ingredient(ExportModelOperationsMixin('ingredient'), models.Model, Permiss
|
||||
space = models.ForeignKey(Space, on_delete=models.CASCADE)
|
||||
objects = ScopedManager(space='space')
|
||||
|
||||
def __str__(self):
|
||||
food = ""
|
||||
unit = ""
|
||||
if self.always_use_plural_food and self.food.plural_name not in (None, "") and not self.no_amount:
|
||||
food = self.food.plural_name
|
||||
else:
|
||||
if self.amount > 1 and self.food.plural_name not in (None, "") and not self.no_amount:
|
||||
food = self.food.plural_name
|
||||
else:
|
||||
food = str(self.food)
|
||||
if self.always_use_plural_unit and self.unit.plural_name not in (None, "") and not self.no_amount:
|
||||
unit = self.unit.plural_name
|
||||
else:
|
||||
if self.amount > 1 and self.unit is not None and self.unit.plural_name not in (None, "") and not self.no_amount:
|
||||
unit = self.unit.plural_name
|
||||
else:
|
||||
unit = str(self.unit)
|
||||
return str(self.amount) + ' ' + str(unit) + ' ' + str(food)
|
||||
|
||||
class Meta:
|
||||
ordering = ['order', 'pk']
|
||||
indexes = (
|
||||
@@ -1142,6 +1128,8 @@ class InviteLink(ExportModelOperationsMixin('invite_link'), models.Model, Permis
|
||||
created_by = models.ForeignKey(User, on_delete=models.CASCADE)
|
||||
created_at = models.DateTimeField(auto_now_add=True)
|
||||
|
||||
internal_note = models.TextField(blank=True, null=True)
|
||||
|
||||
space = models.ForeignKey(Space, on_delete=models.CASCADE)
|
||||
objects = ScopedManager(space='space')
|
||||
|
||||
|
||||
@@ -322,8 +322,8 @@ class UserSpaceSerializer(WritableNestedModelSerializer):
|
||||
|
||||
class Meta:
|
||||
model = UserSpace
|
||||
fields = ('id', 'user', 'space', 'groups', 'active', 'created_at', 'updated_at',)
|
||||
read_only_fields = ('id', 'created_at', 'updated_at', 'space')
|
||||
fields = ('id', 'user', 'space', 'groups', 'active', 'internal_note', 'invite_link', 'created_at', 'updated_at',)
|
||||
read_only_fields = ('id', 'invite_link', 'created_at', 'updated_at', 'space')
|
||||
|
||||
|
||||
class SpacedModelSerializer(serializers.ModelSerializer):
|
||||
@@ -1245,7 +1245,7 @@ class InviteLinkSerializer(WritableNestedModelSerializer):
|
||||
class Meta:
|
||||
model = InviteLink
|
||||
fields = (
|
||||
'id', 'uuid', 'email', 'group', 'valid_until', 'used_by', 'reusable', 'created_by', 'created_at',)
|
||||
'id', 'uuid', 'email', 'group', 'valid_until', 'used_by', 'reusable', 'internal_note', 'created_by', 'created_at',)
|
||||
read_only_fields = ('id', 'uuid', 'created_by', 'created_at',)
|
||||
|
||||
|
||||
@@ -1362,7 +1362,7 @@ class RecipeExportSerializer(WritableNestedModelSerializer):
|
||||
model = Recipe
|
||||
fields = (
|
||||
'name', 'description', 'keywords', 'steps', 'working_time',
|
||||
'waiting_time', 'internal', 'nutrition', 'servings', 'servings_text',
|
||||
'waiting_time', 'internal', 'nutrition', 'servings', 'servings_text', 'source_url',
|
||||
)
|
||||
|
||||
def create(self, validated_data):
|
||||
|
||||
10486
cookbook/static/themes/tandoor_dark.min.css
vendored
Normal file
10486
cookbook/static/themes/tandoor_dark.min.css
vendored
Normal file
File diff suppressed because it is too large
Load Diff
@@ -16,6 +16,7 @@ def theme_url(request):
|
||||
UserPreference.DARKLY: 'themes/darkly.min.css',
|
||||
UserPreference.SUPERHERO: 'themes/superhero.min.css',
|
||||
UserPreference.TANDOOR: 'themes/tandoor.min.css',
|
||||
UserPreference.TANDOOR_DARK: 'themes/tandoor_dark.min.css',
|
||||
}
|
||||
if request.user.userpreference.theme in themes:
|
||||
return static(themes[request.user.userpreference.theme])
|
||||
@@ -26,7 +27,7 @@ def theme_url(request):
|
||||
@register.simple_tag
|
||||
def nav_color(request):
|
||||
if not request.user.is_authenticated:
|
||||
return 'primary'
|
||||
return 'navbar-light bg-primary'
|
||||
|
||||
if request.user.userpreference.nav_color.lower() in ['light', 'warning', 'info', 'success']:
|
||||
return f'navbar-light bg-{request.user.userpreference.nav_color.lower()}'
|
||||
|
||||
@@ -421,6 +421,10 @@ class UserSpaceViewSet(viewsets.ModelViewSet):
|
||||
return super().destroy(request, *args, **kwargs)
|
||||
|
||||
def get_queryset(self):
|
||||
internal_note = self.request.query_params.get('internal_note', None)
|
||||
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):
|
||||
return self.queryset.filter(space=self.request.space)
|
||||
else:
|
||||
@@ -1047,6 +1051,21 @@ class ShoppingListEntryViewSet(viewsets.ModelViewSet):
|
||||
Q(created_by=self.request.user)
|
||||
| Q(shoppinglist__shared=self.request.user)
|
||||
| Q(created_by__in=list(self.request.user.get_shopping_share()))
|
||||
).prefetch_related(
|
||||
'created_by',
|
||||
'food',
|
||||
'food__properties',
|
||||
'food__properties__property_type',
|
||||
'food__inherit_fields',
|
||||
'food__supermarket_category',
|
||||
'food__onhand_users',
|
||||
'food__substitute',
|
||||
'food__child_inherit_fields',
|
||||
|
||||
'unit',
|
||||
'list_recipe',
|
||||
'list_recipe__mealplan',
|
||||
'list_recipe__mealplan__recipe',
|
||||
).distinct().all()
|
||||
|
||||
if pk := self.request.query_params.getlist('id', []):
|
||||
@@ -1165,6 +1184,11 @@ class InviteLinkViewSet(viewsets.ModelViewSet, StandardFilterMixin):
|
||||
permission_classes = [CustomIsSpaceOwner & CustomIsAdmin & CustomTokenHasReadWriteScope]
|
||||
|
||||
def get_queryset(self):
|
||||
|
||||
internal_note = self.request.query_params.get('internal_note', None)
|
||||
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):
|
||||
self.queryset = self.queryset.filter(space=self.request.space).all()
|
||||
return super().get_queryset()
|
||||
|
||||
@@ -370,7 +370,7 @@ def invite_link(request, token):
|
||||
link.used_by = request.user
|
||||
link.save()
|
||||
|
||||
user_space = UserSpace.objects.create(user=request.user, space=link.space, active=False)
|
||||
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
|
||||
|
||||
@@ -2,7 +2,7 @@ version: "2.4"
|
||||
services:
|
||||
db_recipes:
|
||||
restart: always
|
||||
image: postgres:11-alpine
|
||||
image: postgres:15-alpine
|
||||
volumes:
|
||||
- ${POSTGRES_DATA_DIR:-./postgresql}:/var/lib/postgresql/data
|
||||
env_file:
|
||||
@@ -22,6 +22,7 @@ services:
|
||||
- ./.env
|
||||
volumes:
|
||||
- staticfiles:/opt/recipes/staticfiles
|
||||
# Do not make this a bind mount, see https://docs.tandoor.dev/install/docker/#volumes-vs-bind-mounts
|
||||
- nginx_config:/opt/recipes/nginx/conf.d
|
||||
- ${MEDIA_FILES_DIR:-./mediafiles}:/opt/recipes/mediafiles
|
||||
depends_on:
|
||||
@@ -41,6 +42,7 @@ services:
|
||||
depends_on:
|
||||
- web_recipes
|
||||
volumes:
|
||||
# Do not make this a bind mount, see https://docs.tandoor.dev/install/docker/#volumes-vs-bind-mounts
|
||||
- nginx_config:/etc/nginx/conf.d:ro
|
||||
- staticfiles:/static:ro
|
||||
- ${MEDIA_FILES_DIR:-./mediafiles}:/media:ro
|
||||
|
||||
@@ -2,7 +2,7 @@ version: "3"
|
||||
services:
|
||||
db_recipes:
|
||||
restart: always
|
||||
image: postgres:11-alpine
|
||||
image: postgres:15-alpine
|
||||
volumes:
|
||||
- ./postgresql:/var/lib/postgresql/data
|
||||
env_file:
|
||||
@@ -17,6 +17,7 @@ services:
|
||||
- ./.env
|
||||
volumes:
|
||||
- staticfiles:/opt/recipes/staticfiles
|
||||
# Do not make this a bind mount, see https://docs.tandoor.dev/install/docker/#volumes-vs-bind-mounts
|
||||
- nginx_config:/opt/recipes/nginx/conf.d
|
||||
- ./mediafiles:/opt/recipes/mediafiles
|
||||
depends_on:
|
||||
@@ -32,6 +33,7 @@ services:
|
||||
depends_on:
|
||||
- web_recipes
|
||||
volumes:
|
||||
# Do not make this a bind mount, see https://docs.tandoor.dev/install/docker/#volumes-vs-bind-mounts
|
||||
- nginx_config:/etc/nginx/conf.d:ro
|
||||
- staticfiles:/static:ro
|
||||
- ./mediafiles:/media:ro
|
||||
|
||||
@@ -2,7 +2,7 @@ version: "3"
|
||||
services:
|
||||
db_recipes:
|
||||
restart: always
|
||||
image: postgres:11-alpine
|
||||
image: postgres:15-alpine
|
||||
volumes:
|
||||
- ./postgresql:/var/lib/postgresql/data
|
||||
env_file:
|
||||
@@ -15,6 +15,7 @@ services:
|
||||
- ./.env
|
||||
volumes:
|
||||
- staticfiles:/opt/recipes/staticfiles
|
||||
# Do not make this a bind mount, see https://docs.tandoor.dev/install/docker/#volumes-vs-bind-mounts
|
||||
- nginx_config:/opt/recipes/nginx/conf.d
|
||||
- ./mediafiles:/opt/recipes/mediafiles
|
||||
depends_on:
|
||||
@@ -30,6 +31,7 @@ services:
|
||||
depends_on:
|
||||
- web_recipes
|
||||
volumes:
|
||||
# Do not make this a bind mount, see https://docs.tandoor.dev/install/docker/#volumes-vs-bind-mounts
|
||||
- nginx_config:/etc/nginx/conf.d:ro
|
||||
- staticfiles:/static:ro
|
||||
- ./mediafiles:/media:ro
|
||||
|
||||
@@ -2,7 +2,7 @@ version: "3"
|
||||
services:
|
||||
db_recipes:
|
||||
restart: always
|
||||
image: postgres:11-alpine
|
||||
image: postgres:15-alpine
|
||||
volumes:
|
||||
- ./postgresql:/var/lib/postgresql/data
|
||||
env_file:
|
||||
@@ -17,6 +17,7 @@ services:
|
||||
- ./.env
|
||||
volumes:
|
||||
- staticfiles:/opt/recipes/staticfiles
|
||||
# Do not make this a bind mount, see https://docs.tandoor.dev/install/docker/#volumes-vs-bind-mounts
|
||||
- nginx_config:/opt/recipes/nginx/conf.d
|
||||
- ./mediafiles:/opt/recipes/mediafiles
|
||||
depends_on:
|
||||
@@ -30,6 +31,7 @@ services:
|
||||
env_file:
|
||||
- ./.env
|
||||
volumes:
|
||||
# Do not make this a bind mount, see https://docs.tandoor.dev/install/docker/#volumes-vs-bind-mounts
|
||||
- nginx_config:/etc/nginx/conf.d:ro
|
||||
- staticfiles:/static:ro
|
||||
- ./mediafiles:/media:ro
|
||||
|
||||
@@ -69,7 +69,7 @@ services:
|
||||
db_recipes:
|
||||
restart: always
|
||||
container_name: db_recipes
|
||||
image: postgres:11-alpine
|
||||
image: postgres:15-alpine
|
||||
volumes:
|
||||
- ./recipes/db:/var/lib/postgresql/data
|
||||
env_file:
|
||||
|
||||
@@ -80,7 +80,7 @@ Basic guide to setup Docker and Portainer TrueNAS Core.
|
||||
services:
|
||||
db_recipes:
|
||||
restart: always
|
||||
image: postgres:11-alpine
|
||||
image: postgres:15-alpine
|
||||
volumes:
|
||||
- ./postgresql:/var/lib/postgresql/data
|
||||
env_file:
|
||||
@@ -93,7 +93,8 @@ services:
|
||||
- stack.env
|
||||
volumes:
|
||||
- staticfiles:/opt/recipes/staticfiles
|
||||
- nginx_config:/opt/recipes/nginx/conf.d
|
||||
# Do not make this a bind mount, see https://docs.tandoor.dev/install/docker/#volumes-vs-bind-mounts
|
||||
- nginx_config:/opt/recipes/nginx/conf.d
|
||||
- ./mediafiles:/opt/recipes/mediafiles
|
||||
depends_on:
|
||||
- db_recipes
|
||||
@@ -108,6 +109,7 @@ services:
|
||||
depends_on:
|
||||
- web_recipes
|
||||
volumes:
|
||||
# Do not make this a bind mount, see https://docs.tandoor.dev/install/docker/#volumes-vs-bind-mounts
|
||||
- nginx_config:/etc/nginx/conf.d:ro
|
||||
- staticfiles:/static
|
||||
- ./mediafiles:/media
|
||||
|
||||
@@ -128,34 +128,40 @@ INSTALLED_APPS = [
|
||||
'treebeard',
|
||||
]
|
||||
|
||||
PLUGINS_DIRECTORY = os.path.join(BASE_DIR, 'recipes', 'plugins')
|
||||
PLUGINS = []
|
||||
try:
|
||||
for d in os.listdir(os.path.join(BASE_DIR, 'recipes', 'plugins')):
|
||||
if d != '__pycache__':
|
||||
try:
|
||||
apps_path = f'recipes.plugins.{d}.apps'
|
||||
__import__(apps_path)
|
||||
app_config_classname = dir(sys.modules[apps_path])[1]
|
||||
plugin_module = f'recipes.plugins.{d}.apps.{app_config_classname}'
|
||||
if plugin_module not in INSTALLED_APPS:
|
||||
INSTALLED_APPS.append(plugin_module)
|
||||
plugin_class = getattr(
|
||||
sys.modules[apps_path], app_config_classname)
|
||||
plugin_config = {
|
||||
'name': plugin_class.verbose_name if hasattr(plugin_class, 'verbose_name') else plugin_class.name,
|
||||
'module': f'recipes.plugins.{d}',
|
||||
'base_path': os.path.join(BASE_DIR, 'recipes', 'plugins', d),
|
||||
'base_url': plugin_class.base_url,
|
||||
'bundle_name': plugin_class.bundle_name if hasattr(plugin_class, 'bundle_name') else '',
|
||||
'api_router_name': plugin_class.api_router_name if hasattr(plugin_class, 'api_router_name') else '',
|
||||
'nav_main': plugin_class.nav_main if hasattr(plugin_class, 'nav_main') else '',
|
||||
'nav_dropdown': plugin_class.nav_dropdown if hasattr(plugin_class, 'nav_dropdown') else '',
|
||||
}
|
||||
PLUGINS.append(plugin_config)
|
||||
except Exception:
|
||||
if DEBUG:
|
||||
traceback.print_exc()
|
||||
print(f'ERROR failed to initialize plugin {d}')
|
||||
if os.path.isdir(PLUGINS_DIRECTORY):
|
||||
for d in os.listdir(PLUGINS_DIRECTORY):
|
||||
if d != '__pycache__':
|
||||
try:
|
||||
apps_path = f'recipes.plugins.{d}.apps'
|
||||
__import__(apps_path)
|
||||
app_config_classname = dir(sys.modules[apps_path])[1]
|
||||
plugin_module = f'recipes.plugins.{d}.apps.{app_config_classname}'
|
||||
plugin_class = getattr(sys.modules[apps_path], app_config_classname)
|
||||
plugin_disabled = False
|
||||
if hasattr(plugin_class, 'disabled'):
|
||||
plugin_disabled = plugin_class.disabled
|
||||
if plugin_module not in INSTALLED_APPS and not plugin_disabled:
|
||||
INSTALLED_APPS.append(plugin_module)
|
||||
|
||||
plugin_config = {
|
||||
'name': plugin_class.verbose_name if hasattr(plugin_class, 'verbose_name') else plugin_class.name,
|
||||
'module': f'recipes.plugins.{d}',
|
||||
'base_path': os.path.join(BASE_DIR, 'recipes', 'plugins', d),
|
||||
'base_url': plugin_class.base_url,
|
||||
'bundle_name': plugin_class.bundle_name if hasattr(plugin_class, 'bundle_name') else '',
|
||||
'api_router_name': plugin_class.api_router_name if hasattr(plugin_class, 'api_router_name') else '',
|
||||
'nav_main': plugin_class.nav_main if hasattr(plugin_class, 'nav_main') else '',
|
||||
'nav_dropdown': plugin_class.nav_dropdown if hasattr(plugin_class, 'nav_dropdown') else '',
|
||||
}
|
||||
PLUGINS.append(plugin_config)
|
||||
print(f'PLUGIN {d} loaded')
|
||||
except Exception:
|
||||
if DEBUG:
|
||||
traceback.print_exc()
|
||||
print(f'ERROR failed to initialize plugin {d}')
|
||||
except Exception:
|
||||
if DEBUG:
|
||||
print('ERROR failed to initialize plugins')
|
||||
@@ -522,4 +528,4 @@ DEFAULT_FROM_EMAIL = os.getenv('DEFAULT_FROM_EMAIL', 'webmaster@localhost')
|
||||
ACCOUNT_EMAIL_SUBJECT_PREFIX = os.getenv(
|
||||
'ACCOUNT_EMAIL_SUBJECT_PREFIX', '[Tandoor Recipes] ') # allauth sender prefix
|
||||
|
||||
mimetypes.add_type("text/javascript", ".js", True)
|
||||
mimetypes.add_type("text/javascript", ".js", True)
|
||||
|
||||
@@ -1254,23 +1254,28 @@ export default {
|
||||
ing_list.forEach((ing) => {
|
||||
if (ing.trim() !== "") {
|
||||
promises.push(this.genericPostAPI("api_ingredient_from_string", {text: ing}).then((result) => {
|
||||
|
||||
let unit = null
|
||||
if (result.data.unit !== "" && result.data.unit !== null) {
|
||||
unit = {name: result.data.unit}
|
||||
}
|
||||
parsed_ing_list.push({
|
||||
let new_ingredient = {
|
||||
amount: result.data.amount,
|
||||
unit: unit,
|
||||
food: {name: result.data.food},
|
||||
note: result.data.note,
|
||||
original_text: ing,
|
||||
})
|
||||
}
|
||||
console.log(ing, new_ingredient)
|
||||
parsed_ing_list.push(new_ingredient)
|
||||
}))
|
||||
}
|
||||
})
|
||||
Promise.allSettled(promises).then(() => {
|
||||
ing_list.forEach(ing => {
|
||||
step.ingredients.push(parsed_ing_list.find(x => x.original_text === ing))
|
||||
if(ing.trim() !== ""){
|
||||
step.ingredients.push(parsed_ing_list.find(x => x.original_text === ing))
|
||||
}
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
@@ -71,8 +71,8 @@
|
||||
}}</span></span>
|
||||
</td>
|
||||
<td>
|
||||
<button class="btn btn-danger btn-small" @click="deleteProperty(fp)"><i
|
||||
class="fas fa-trash-alt"></i></button>
|
||||
<a class="btn btn-danger btn-small" @click="deleteProperty(fp)"><i
|
||||
class="fas fa-trash-alt"></i></a>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
@@ -293,7 +293,9 @@ export default {
|
||||
if (this.item1.id !== undefined) {
|
||||
pf = apiClient.retrieveFood(this.item1.id).then((r) => {
|
||||
this.food = r.data
|
||||
this.food.properties_food_unit = {name: 'g'}
|
||||
if (this.food.properties_food_unit === null) {
|
||||
this.food.properties_food_unit = {name: 'g'}
|
||||
}
|
||||
}).catch(err => {
|
||||
StandardToasts.makeStandardToast(this, StandardToasts.FAIL_FETCH, err)
|
||||
})
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div>
|
||||
<b-form-group v-bind:label="label" class="mb-3">
|
||||
<b-form-group v-bind:label="field_label" class="mb-3">
|
||||
<b-form-select v-model="new_value" :placeholder="placeholder" :options="translatedOptions"></b-form-select>
|
||||
</b-form-group>
|
||||
</div>
|
||||
@@ -10,12 +10,13 @@
|
||||
export default {
|
||||
name: "ChoiceInput",
|
||||
props: {
|
||||
field: { type: String, default: "You Forgot To Set Field Name" },
|
||||
label: { type: String, default: "Text Field" },
|
||||
value: { type: String, default: "" },
|
||||
field: {type: String, default: "You Forgot To Set Field Name"},
|
||||
label: {type: String, default: "Text Field"},
|
||||
value: {type: String, default: ""},
|
||||
options: [],
|
||||
placeholder: { type: String, default: "You Should Add Placeholder Text" },
|
||||
show_merge: { type: Boolean, default: false },
|
||||
placeholder: {type: String, default: "You Should Add Placeholder Text"},
|
||||
show_merge: {type: Boolean, default: false},
|
||||
optional: {type: Boolean, default: false},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
@@ -31,9 +32,16 @@ export default {
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
field_label: function () {
|
||||
if (this.optional) {
|
||||
return this.label
|
||||
} else {
|
||||
return this.label + '*'
|
||||
}
|
||||
},
|
||||
translatedOptions() {
|
||||
return this.options.map((x) => {
|
||||
return { ...x, text: this.$t(x.text) }
|
||||
return {...x, text: this.$t(x.text)}
|
||||
})
|
||||
},
|
||||
},
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div>
|
||||
<b-form-group v-bind:label="label" class="mb-3">
|
||||
<b-form-group v-bind:label="field_label" class="mb-3">
|
||||
<b-form-input v-model="new_value" type="date" ></b-form-input>
|
||||
<em v-if="help" class="small text-muted">{{ help }}</em>
|
||||
<small v-if="subtitle" class="text-muted">{{ subtitle }}</small>
|
||||
@@ -17,6 +17,16 @@ export default {
|
||||
value: { type: String, default: "" },
|
||||
help: { type: String, default: undefined },
|
||||
subtitle: { type: String, default: undefined },
|
||||
optional: {type: Boolean, default: false},
|
||||
},
|
||||
computed: {
|
||||
field_label: function () {
|
||||
if (this.optional) {
|
||||
return this.label
|
||||
} else {
|
||||
return this.label + '*'
|
||||
}
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div>
|
||||
<b-form-group
|
||||
v-bind:label="label"
|
||||
v-bind:label="field_label"
|
||||
class="mb-3">
|
||||
|
||||
<input class="form-control" v-model="new_value">
|
||||
@@ -27,6 +27,7 @@ export default {
|
||||
field: {type: String, default: 'You Forgot To Set Field Name'},
|
||||
label: {type: String, default: ''},
|
||||
value: {type: String, default: ''},
|
||||
optional: {type: Boolean, default: false},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
@@ -36,6 +37,15 @@ export default {
|
||||
emojisOutput: ""
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
field_label: function () {
|
||||
if (this.optional) {
|
||||
return this.label
|
||||
} else {
|
||||
return this.label + '*'
|
||||
}
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
'new_value': function () {
|
||||
this.$root.$emit('change', this.field, this.new_value ?? null)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div>
|
||||
<b-form-group
|
||||
v-bind:label="label"
|
||||
v-bind:label="field_label"
|
||||
class="mb-3">
|
||||
<b-form-file
|
||||
v-model="new_value"
|
||||
@@ -30,7 +30,17 @@ export default {
|
||||
value: {type: String, default: ''},
|
||||
placeholder: {type: String, default: ''},
|
||||
show_merge: {type: Boolean, default: false},
|
||||
optional: {type: Boolean, default: false},
|
||||
},
|
||||
computed: {
|
||||
field_label: function () {
|
||||
if (this.optional) {
|
||||
return this.label
|
||||
} else {
|
||||
return this.label + '*'
|
||||
}
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
new_value: undefined,
|
||||
|
||||
@@ -11,15 +11,16 @@
|
||||
</template>
|
||||
<div v-for="(f, i) in form.fields" v-bind:key="i">
|
||||
<p v-if="visibleCondition(f, 'instruction')">{{ f.label }}</p>
|
||||
<lookup-input v-if="visibleCondition(f, 'lookup')" :form="f" :model="listModel(f.list)" @change="storeValue" :help="showHelp && f.help"/>
|
||||
<lookup-input v-if="visibleCondition(f, 'lookup')" :form="f" :model="listModel(f.list)" @change="storeValue" :help="showHelp && f.help" :optional="f.optional"/>
|
||||
<checkbox-input class="mb-3" v-if="visibleCondition(f, 'checkbox')" :label="f.label" :value="f.value" :field="f.field" :help="showHelp && f.help"/>
|
||||
<text-input v-if="visibleCondition(f, 'text')" :label="f.label" :value="f.value" :field="f.field" :placeholder="f.placeholder" :help="showHelp && f.help" :subtitle="f.subtitle" :disabled="f.disabled"/>
|
||||
<choice-input v-if="visibleCondition(f, 'choice')" :label="f.label" :value="f.value" :field="f.field" :options="f.options" :placeholder="f.placeholder"/>
|
||||
<emoji-input v-if="visibleCondition(f, 'emoji')" :label="f.label" :value="f.value" :field="f.field" @change="storeValue"/>
|
||||
<file-input v-if="visibleCondition(f, 'file')" :label="f.label" :value="f.value" :field="f.field" @change="storeValue"/>
|
||||
<small-text v-if="visibleCondition(f, 'smalltext')" :value="f.value"/>
|
||||
<date-input v-if="visibleCondition(f, 'date')" :label="f.label" :value="f.value" :field="f.field" :help="showHelp && f.help" :subtitle="f.subtitle"/>
|
||||
<number-input v-if="visibleCondition(f, 'number')" :label="f.label" :value="f.value" :field="f.field" :placeholder="f.placeholder" :help="showHelp && f.help" :subtitle="f.subtitle"/>
|
||||
<text-input v-if="visibleCondition(f, 'text')" :label="f.label" :value="f.value" :field="f.field" :placeholder="f.placeholder" :help="showHelp && f.help" :subtitle="f.subtitle" :disabled="f.disabled" :optional="f.optional"/>
|
||||
<text-area-input v-if="visibleCondition(f, 'textarea')" :label="f.label" :value="f.value" :field="f.field" :placeholder="f.placeholder" :help="showHelp && f.help" :subtitle="f.subtitle" :disabled="f.disabled" :optional="f.optional"/>
|
||||
<choice-input v-if="visibleCondition(f, 'choice')" :label="f.label" :value="f.value" :field="f.field" :options="f.options" :placeholder="f.placeholder" :optional="f.optional"/>
|
||||
<emoji-input v-if="visibleCondition(f, 'emoji')" :label="f.label" :value="f.value" :field="f.field" @change="storeValue" :optional="f.optional"/>
|
||||
<file-input v-if="visibleCondition(f, 'file')" :label="f.label" :value="f.value" :field="f.field" @change="storeValue" :optional="f.optional"/>
|
||||
<small-text v-if="visibleCondition(f, 'smalltext')" :value="f.value" />
|
||||
<date-input v-if="visibleCondition(f, 'date')" :label="f.label" :value="f.value" :field="f.field" :help="showHelp && f.help" :subtitle="f.subtitle" :optional="f.optional"/>
|
||||
<number-input v-if="visibleCondition(f, 'number')" :label="f.label" :value="f.value" :field="f.field" :placeholder="f.placeholder" :help="showHelp && f.help" :subtitle="f.subtitle" :optional="f.optional"/>
|
||||
</div>
|
||||
<template v-slot:modal-footer>
|
||||
<div class="row w-100">
|
||||
@@ -57,6 +58,7 @@ import FileInput from "@/components/Modals/FileInput"
|
||||
import SmallText from "@/components/Modals/SmallText"
|
||||
import HelpBadge from "@/components/Badges/Help"
|
||||
import NumberInput from "@/components/Modals/NumberInput.vue";
|
||||
import TextAreaInput from "@/components/Modals/TextAreaInput.vue";
|
||||
|
||||
export default {
|
||||
name: "GenericModalForm",
|
||||
@@ -70,7 +72,8 @@ export default {
|
||||
SmallText,
|
||||
HelpBadge,
|
||||
DateInput,
|
||||
NumberInput
|
||||
NumberInput,
|
||||
TextAreaInput
|
||||
},
|
||||
mixins: [ApiMixin, ToastMixin],
|
||||
props: {
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<div>
|
||||
<b-form-group :class="class_list">
|
||||
<template #label v-if="show_label">
|
||||
{{ form.label }}
|
||||
{{ field_label }}
|
||||
</template>
|
||||
<generic-multiselect
|
||||
@change="new_value = $event.val"
|
||||
@@ -27,11 +27,11 @@
|
||||
|
||||
<script>
|
||||
import GenericMultiselect from "@/components/GenericMultiselect"
|
||||
import { StandardToasts, ApiMixin } from "@/utils/utils"
|
||||
import {StandardToasts, ApiMixin} from "@/utils/utils"
|
||||
|
||||
export default {
|
||||
name: "LookupInput",
|
||||
components: { GenericMultiselect },
|
||||
components: {GenericMultiselect},
|
||||
mixins: [ApiMixin],
|
||||
props: {
|
||||
form: {
|
||||
@@ -46,11 +46,13 @@ export default {
|
||||
return undefined
|
||||
},
|
||||
},
|
||||
class_list: { type: String, default: "mb-3" },
|
||||
show_label: { type: Boolean, default: true },
|
||||
clear: { type: Number },
|
||||
help: { type: String, default: undefined },
|
||||
class_list: {type: String, default: "mb-3"},
|
||||
show_label: {type: Boolean, default: true},
|
||||
clear: {type: Number},
|
||||
help: {type: String, default: undefined},
|
||||
optional: {type: Boolean, default: false},
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
new_value: undefined,
|
||||
@@ -67,7 +69,7 @@ export default {
|
||||
this.label = this.form?.label ?? ""
|
||||
this.sticky_options = this.form?.sticky_options ?? []
|
||||
this.sticky_options = this.sticky_options.map((x) => {
|
||||
return { ...x, name: this.$t(x.name) }
|
||||
return {...x, name: this.$t(x.name)}
|
||||
})
|
||||
this.list_label = this.form?.list_label ?? undefined
|
||||
if (this.list_label?.includes("::")) {
|
||||
@@ -75,6 +77,13 @@ export default {
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
field_label: function () {
|
||||
if (this.optional) {
|
||||
return this.form.label
|
||||
} else {
|
||||
return this.form.label + '*'
|
||||
}
|
||||
},
|
||||
modelName() {
|
||||
return this.$t(this?.model?.name) ?? this.$t("Search")
|
||||
},
|
||||
@@ -124,7 +133,7 @@ export default {
|
||||
let item = undefined
|
||||
let label = this.form.list_label.split("::")
|
||||
itemlist.forEach((x) => {
|
||||
item = { ...x }
|
||||
item = {...x}
|
||||
for (const [k, v] of Object.entries(x)) {
|
||||
if (k == label[0]) {
|
||||
item["id"] = v.id
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div>
|
||||
<b-form-group v-bind:label="label" class="mb-3">
|
||||
<b-form-group v-bind:label="field_label" class="mb-3">
|
||||
<b-form-input v-model="new_value" type="number" :placeholder="placeholder"></b-form-input>
|
||||
<em v-if="help" class="small text-muted">{{ help }}</em>
|
||||
<small v-if="subtitle" class="text-muted">{{ subtitle }}</small>
|
||||
@@ -18,6 +18,16 @@ export default {
|
||||
placeholder: { type: Number, default: 0 },
|
||||
help: { type: String, default: undefined },
|
||||
subtitle: { type: String, default: undefined },
|
||||
optional: {type: Boolean, default: false},
|
||||
},
|
||||
computed: {
|
||||
field_label: function () {
|
||||
if (this.optional) {
|
||||
return this.label
|
||||
} else {
|
||||
return this.label + '*'
|
||||
}
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
|
||||
48
vue/src/components/Modals/TextAreaInput.vue
Normal file
48
vue/src/components/Modals/TextAreaInput.vue
Normal file
@@ -0,0 +1,48 @@
|
||||
<template>
|
||||
<div>
|
||||
<b-form-group v-bind:label="field_label" class="mb-3">
|
||||
<b-form-textarea v-model="new_value" type="text" :placeholder="placeholder" :disabled="disabled"></b-form-textarea>
|
||||
<em v-if="help" class="small text-muted">{{ help }}</em>
|
||||
<small v-if="subtitle" class="text-muted">{{ subtitle }}</small>
|
||||
</b-form-group>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "TextAreaInput",
|
||||
props: {
|
||||
field: {type: String, default: "You Forgot To Set Field Name"},
|
||||
label: {type: String, default: "Text Field"},
|
||||
value: {type: String, default: ""},
|
||||
placeholder: {type: String, default: "You Should Add Placeholder Text"},
|
||||
help: {type: String, default: undefined},
|
||||
subtitle: {type: String, default: undefined},
|
||||
disabled: {type: Boolean, default: false},
|
||||
optional: {type: Boolean, default: false},
|
||||
},
|
||||
computed: {
|
||||
field_label: function () {
|
||||
if (this.optional) {
|
||||
return this.label
|
||||
} else {
|
||||
return this.label + '*'
|
||||
}
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
new_value: undefined,
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.new_value = this.value
|
||||
},
|
||||
watch: {
|
||||
new_value: function () {
|
||||
this.$root.$emit("change", this.field, this.new_value)
|
||||
},
|
||||
},
|
||||
methods: {},
|
||||
}
|
||||
</script>
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div>
|
||||
<b-form-group v-bind:label="label" class="mb-3">
|
||||
<b-form-group v-bind:label="field_label" class="mb-3">
|
||||
<b-form-input v-model="new_value" type="text" :placeholder="placeholder" :disabled="disabled"></b-form-input>
|
||||
<em v-if="help" class="small text-muted">{{ help }}</em>
|
||||
<small v-if="subtitle" class="text-muted">{{ subtitle }}</small>
|
||||
@@ -18,13 +18,23 @@ export default {
|
||||
placeholder: { type: String, default: "You Should Add Placeholder Text" },
|
||||
help: { type: String, default: undefined },
|
||||
subtitle: { type: String, default: undefined },
|
||||
disabled: { type: Boolean, default: false }
|
||||
disabled: { type: Boolean, default: false },
|
||||
optional: {type: Boolean, default: false},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
new_value: undefined,
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
field_label: function () {
|
||||
if (this.optional) {
|
||||
return this.label
|
||||
} else {
|
||||
return this.label + '*'
|
||||
}
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.new_value = this.value
|
||||
},
|
||||
|
||||
@@ -50,6 +50,7 @@
|
||||
<b-form-select-option value="DARKLY">Darkly</b-form-select-option>
|
||||
<b-form-select-option value="FLATLY">Flatly</b-form-select-option>
|
||||
<b-form-select-option value="SUPERHERO">Superhero</b-form-select-option>
|
||||
<b-form-select-option value="TANDOOR_DARK">Tandoor Dark (INCOMPLETE)</b-form-select-option>
|
||||
</b-form-select>
|
||||
|
||||
</b-form-group>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"warning_feature_beta": "",
|
||||
"warning_feature_beta": "Tato funkce je momentálně ve fázi Beta (testování). Očekávejte, prosím, chyby. V budoucnosti může dojít i ke ztrátě dat.",
|
||||
"err_fetching_resource": "",
|
||||
"err_creating_resource": "",
|
||||
"err_updating_resource": "",
|
||||
@@ -13,395 +13,395 @@
|
||||
"success_deleting_resource": "",
|
||||
"success_moving_resource": "",
|
||||
"success_merging_resource": "",
|
||||
"file_upload_disabled": "",
|
||||
"warning_space_delete": "",
|
||||
"file_upload_disabled": "Nahrávání souborů není povoleno pro Váš prostor.",
|
||||
"warning_space_delete": "Můžete smazat váš prostor včetně všech receptů, nákupních seznamů, jídelníčků a všeho ostatního, co jste vytvořili. Tuto akci nemůžete vzít zpět! Jste si jisti, že chcete pokračovat?",
|
||||
"food_inherit_info": "",
|
||||
"facet_count_info": "",
|
||||
"step_time_minutes": "",
|
||||
"confirm_delete": "",
|
||||
"import_running": "",
|
||||
"all_fields_optional": "",
|
||||
"convert_internal": "",
|
||||
"show_only_internal": "",
|
||||
"show_split_screen": "",
|
||||
"facet_count_info": "Zobraz počet receptů u filtrů vyhledávání.",
|
||||
"step_time_minutes": "Nastavte čas v minutách",
|
||||
"confirm_delete": "Jste si jisti že chcete odstranit tento {objekt}?",
|
||||
"import_running": "Probíhá import, čekejte prosím!",
|
||||
"all_fields_optional": "Všechna pole jsou nepviná a mohou být ponechána prázdná.",
|
||||
"convert_internal": "Převést na interní recept",
|
||||
"show_only_internal": "Zobrazit pouze interní recepty",
|
||||
"show_split_screen": "Rozdělené zobrazení",
|
||||
"Log_Recipe_Cooking": "",
|
||||
"External_Recipe_Image": "",
|
||||
"Add_to_Shopping": "",
|
||||
"Add_to_Plan": "",
|
||||
"Step_start_time": "",
|
||||
"Sort_by_new": "",
|
||||
"Table_of_Contents": "",
|
||||
"External_Recipe_Image": "Externí obrázek receptu",
|
||||
"Add_to_Shopping": "Přidat k nákupu",
|
||||
"Add_to_Plan": "Přidat do jídelníčku",
|
||||
"Step_start_time": "Nastav počáteční čas",
|
||||
"Sort_by_new": "Seřadit od nejnovějšího",
|
||||
"Table_of_Contents": "Obsah",
|
||||
"Recipes_per_page": "Receptů na stránku",
|
||||
"Show_as_header": "",
|
||||
"Hide_as_header": "",
|
||||
"Show_as_header": "Nastav jako nadpis",
|
||||
"Hide_as_header": "Skryj jako nadpis",
|
||||
"Add_nutrition_recipe": "Přidat nutriční hodnoty",
|
||||
"Remove_nutrition_recipe": "Smazat nutriční hodnoty",
|
||||
"Copy_template_reference": "",
|
||||
"Save_and_View": "Uložit & Zobrazit",
|
||||
"Manage_Books": "",
|
||||
"Manage_Books": "Spravovat kuchařky",
|
||||
"Meal_Plan": "Jídelníček",
|
||||
"Select_Book": "",
|
||||
"Select_Book": "Vyber kuchařku",
|
||||
"Select_File": "Vybrat soubor",
|
||||
"Recipe_Image": "",
|
||||
"Recipe_Image": "Obrázek k receptu",
|
||||
"Import_finished": "Import dokončen",
|
||||
"View_Recipes": "Zobrazit recepty",
|
||||
"Log_Cooking": "",
|
||||
"New_Recipe": "Nový recept",
|
||||
"Url_Import": "",
|
||||
"Reset_Search": "",
|
||||
"Recently_Viewed": "",
|
||||
"Load_More": "",
|
||||
"New_Keyword": "",
|
||||
"Delete_Keyword": "",
|
||||
"Edit_Keyword": "",
|
||||
"Url_Import": "Import pomocí URL odkazu",
|
||||
"Reset_Search": "Zrušit filtry vyhledávání",
|
||||
"Recently_Viewed": "Naposledy prohlížené",
|
||||
"Load_More": "Načíst další",
|
||||
"New_Keyword": "Nové klíčové slovo",
|
||||
"Delete_Keyword": "Smazat klíčové slovo",
|
||||
"Edit_Keyword": "Upravit klíčové slovo",
|
||||
"Edit_Recipe": "Upravit recept",
|
||||
"Move_Keyword": "",
|
||||
"Merge_Keyword": "",
|
||||
"Hide_Keywords": "",
|
||||
"Hide_Recipes": "",
|
||||
"Move_Keyword": "Přesunout klíčové slovo",
|
||||
"Merge_Keyword": "Sloučit klíčové slovo",
|
||||
"Hide_Keywords": "Skrýt klíčové slovo",
|
||||
"Hide_Recipes": "Skrýt recept",
|
||||
"Move_Up": "Nahoru",
|
||||
"Move_Down": "Dolů",
|
||||
"Step_Name": "Název kroku",
|
||||
"Step_Type": "",
|
||||
"Make_Header": "",
|
||||
"Make_Ingredient": "",
|
||||
"Step_Type": "Druh kroku",
|
||||
"Make_Header": "Použij jako nadpis",
|
||||
"Make_Ingredient": "Použij jako ingredienci",
|
||||
"Amount": "Množství",
|
||||
"Enable_Amount": "Zobrazit množství",
|
||||
"Disable_Amount": "Skrýt množství",
|
||||
"Ingredient Editor": "Editace ingrediencí",
|
||||
"Description_Replace": "",
|
||||
"Instruction_Replace": "",
|
||||
"Auto_Sort": "",
|
||||
"Auto_Sort_Help": "",
|
||||
"Private_Recipe": "",
|
||||
"Private_Recipe_Help": "",
|
||||
"reusable_help_text": "",
|
||||
"Add_Step": "",
|
||||
"Keywords": "",
|
||||
"Books": "",
|
||||
"Description_Replace": "Nahraď popis",
|
||||
"Instruction_Replace": "Nahraď instrukce",
|
||||
"Auto_Sort": "Automatické řazení",
|
||||
"Auto_Sort_Help": "Přiřadit všechny ingredience k nejlépe vyhovujícímu kroku.",
|
||||
"Private_Recipe": "Soukromý recept",
|
||||
"Private_Recipe_Help": "Recept můžete zobrazit pouze vy a lidé, se kterými jej sdílíte.",
|
||||
"reusable_help_text": "Má-li pozvánka platit pro více než jednoho uživatele.",
|
||||
"Add_Step": "Přidat krok",
|
||||
"Keywords": "Klíčová slova",
|
||||
"Books": "Kuchařky",
|
||||
"Proteins": "Proteiny",
|
||||
"Fats": "Tuky",
|
||||
"Carbohydrates": "",
|
||||
"Calories": "",
|
||||
"Energy": "",
|
||||
"Carbohydrates": "Sacharidy",
|
||||
"Calories": "Kalorie",
|
||||
"Energy": "Energie",
|
||||
"Nutrition": "",
|
||||
"Date": "",
|
||||
"Share": "",
|
||||
"Automation": "",
|
||||
"Parameter": "",
|
||||
"Export": "",
|
||||
"Copy": "",
|
||||
"Rating": "",
|
||||
"Close": "",
|
||||
"Cancel": "",
|
||||
"Link": "",
|
||||
"Add": "",
|
||||
"New": "",
|
||||
"Note": "",
|
||||
"Success": "",
|
||||
"Failure": "",
|
||||
"Protected": "",
|
||||
"Ingredients": "",
|
||||
"Date": "Datum",
|
||||
"Share": "Sdílet",
|
||||
"Automation": "Automatizace",
|
||||
"Parameter": "Parametr",
|
||||
"Export": "Export",
|
||||
"Copy": "Kopírovat",
|
||||
"Rating": "Hodnocení",
|
||||
"Close": "Zavřít",
|
||||
"Cancel": "Zrušit",
|
||||
"Link": "Odkaz",
|
||||
"Add": "Přidat",
|
||||
"New": "Nový",
|
||||
"Note": "Poznámka",
|
||||
"Success": "Úspěch",
|
||||
"Failure": "Selhání",
|
||||
"Protected": "Chráněný",
|
||||
"Ingredients": "Ingredience",
|
||||
"Supermarket": "",
|
||||
"Categories": "",
|
||||
"Category": "",
|
||||
"Selected": "",
|
||||
"min": "",
|
||||
"Servings": "",
|
||||
"Categories": "Kategorie",
|
||||
"Category": "Kategorie",
|
||||
"Selected": "Vybrané",
|
||||
"min": "min",
|
||||
"Servings": "Porce",
|
||||
"Waiting": "",
|
||||
"Preparation": "",
|
||||
"External": "",
|
||||
"Size": "",
|
||||
"Files": "",
|
||||
"File": "",
|
||||
"Edit": "",
|
||||
"Image": "",
|
||||
"Delete": "",
|
||||
"Open": "",
|
||||
"Ok": "",
|
||||
"Save": "",
|
||||
"Step": "",
|
||||
"Search": "",
|
||||
"Import": "",
|
||||
"Print": "",
|
||||
"Settings": "",
|
||||
"or": "",
|
||||
"and": "",
|
||||
"Information": "",
|
||||
"Download": "",
|
||||
"Create": "",
|
||||
"Search Settings": "",
|
||||
"View": "",
|
||||
"Recipes": "",
|
||||
"Move": "",
|
||||
"Merge": "",
|
||||
"Parent": "",
|
||||
"Copy Link": "",
|
||||
"Copy Token": "",
|
||||
"delete_confirmation": "",
|
||||
"move_confirmation": "",
|
||||
"merge_confirmation": "",
|
||||
"create_rule": "",
|
||||
"move_selection": "",
|
||||
"merge_selection": "",
|
||||
"Preparation": "Příprava",
|
||||
"External": "Externí",
|
||||
"Size": "Velikost",
|
||||
"Files": "Soubory",
|
||||
"File": "Soubor",
|
||||
"Edit": "Upravit",
|
||||
"Image": "Obrázek",
|
||||
"Delete": "Smazat",
|
||||
"Open": "Otevřít",
|
||||
"Ok": "Ok",
|
||||
"Save": "Uložit",
|
||||
"Step": "Krok",
|
||||
"Search": "Hledat",
|
||||
"Import": "Import",
|
||||
"Print": "Tisk",
|
||||
"Settings": "Nastavení",
|
||||
"or": "nebo",
|
||||
"and": "a",
|
||||
"Information": "Informace",
|
||||
"Download": "Stáhnout",
|
||||
"Create": "Vytvořit",
|
||||
"Search Settings": "Nastavení vyhledávání",
|
||||
"View": "Zobrazit",
|
||||
"Recipes": "Recepty",
|
||||
"Move": "Přesunout",
|
||||
"Merge": "Spojit",
|
||||
"Parent": "Nadřazená",
|
||||
"Copy Link": "Kopírovat odkaz",
|
||||
"Copy Token": "Kopírovat token",
|
||||
"delete_confirmation": "Jste si jistí, že chcete smazat {source}?",
|
||||
"move_confirmation": "Přesunout <i>{child}</i> do nadřazené <i>{parent}</i>",
|
||||
"merge_confirmation": "Nahradit <i>{source}</i> za <i>{target}</i>",
|
||||
"create_rule": "a vytvořit automatizaci",
|
||||
"move_selection": "Vybrat nadřazený {type} kam {source} přesunout.",
|
||||
"merge_selection": "Nahradit všechny výskyty {source} za vybraný {type}.",
|
||||
"Root": "",
|
||||
"Ignore_Shopping": "",
|
||||
"Shopping_Category": "",
|
||||
"Shopping_Categories": "",
|
||||
"Edit_Food": "",
|
||||
"Move_Food": "",
|
||||
"New_Food": "",
|
||||
"Hide_Food": "",
|
||||
"Food_Alias": "",
|
||||
"Unit_Alias": "",
|
||||
"Keyword_Alias": "",
|
||||
"Delete_Food": "",
|
||||
"No_ID": "",
|
||||
"Meal_Plan_Days": "",
|
||||
"merge_title": "",
|
||||
"move_title": "",
|
||||
"Food": "",
|
||||
"Original_Text": "",
|
||||
"Recipe_Book": "",
|
||||
"Ignore_Shopping": "Ignorovat nákupní seznam",
|
||||
"Shopping_Category": "Kategorie nákupního seznamu",
|
||||
"Shopping_Categories": "Kategorie nákupního seznamu",
|
||||
"Edit_Food": "Upravit jídlo",
|
||||
"Move_Food": "Přesunout jídlo",
|
||||
"New_Food": "Nové jídlo",
|
||||
"Hide_Food": "Skrýt jídlo",
|
||||
"Food_Alias": "Přezdívka jídla",
|
||||
"Unit_Alias": "Přezdívka jednotky",
|
||||
"Keyword_Alias": "Přezdívka klíčového slova",
|
||||
"Delete_Food": "Smazat jídlo",
|
||||
"No_ID": "ID nenalezeno, odstranění není možné.",
|
||||
"Meal_Plan_Days": "Budoucí jídelníčky",
|
||||
"merge_title": "Sloučit {type}",
|
||||
"move_title": "Přesunout {type}",
|
||||
"Food": "Jídlo",
|
||||
"Original_Text": "Původní text",
|
||||
"Recipe_Book": "Kuchařka",
|
||||
"del_confirmation_tree": "",
|
||||
"delete_title": "",
|
||||
"create_title": "",
|
||||
"edit_title": "",
|
||||
"Name": "",
|
||||
"Type": "",
|
||||
"Description": "",
|
||||
"Recipe": "",
|
||||
"delete_title": "Smazat {type}",
|
||||
"create_title": "Nový {type}",
|
||||
"edit_title": "Upravit {type}",
|
||||
"Name": "Jméno",
|
||||
"Type": "Typ",
|
||||
"Description": "Popis",
|
||||
"Recipe": "Recept",
|
||||
"tree_root": "",
|
||||
"Icon": "",
|
||||
"Unit": "",
|
||||
"Decimals": "",
|
||||
"Default_Unit": "",
|
||||
"No_Results": "",
|
||||
"New_Unit": "",
|
||||
"Create_New_Shopping Category": "",
|
||||
"Create_New_Food": "",
|
||||
"Create_New_Keyword": "",
|
||||
"Create_New_Unit": "",
|
||||
"Create_New_Meal_Type": "",
|
||||
"Create_New_Shopping_Category": "",
|
||||
"and_up": "",
|
||||
"and_down": "",
|
||||
"Instructions": "",
|
||||
"Unrated": "",
|
||||
"Automate": "",
|
||||
"Empty": "",
|
||||
"Key_Ctrl": "",
|
||||
"Key_Shift": "",
|
||||
"Time": "",
|
||||
"Text": "",
|
||||
"Shopping_list": "",
|
||||
"Added_by": "",
|
||||
"Icon": "Ikona",
|
||||
"Unit": "Jednotka",
|
||||
"Decimals": "Desetinná místa",
|
||||
"Default_Unit": "Výchozí jednotka",
|
||||
"No_Results": "Žádné výsledky",
|
||||
"New_Unit": "Nová jednotka",
|
||||
"Create_New_Shopping Category": "Vytvořit novou nákupní kategorii",
|
||||
"Create_New_Food": "Přidat nové jídlo",
|
||||
"Create_New_Keyword": "Přidat nové klíčové slovo",
|
||||
"Create_New_Unit": "Přidat novou jednotku",
|
||||
"Create_New_Meal_Type": "Přidat nový druh jídla",
|
||||
"Create_New_Shopping_Category": "Přidat novou nákupní kategorii",
|
||||
"and_up": "a nahoru",
|
||||
"and_down": "a dolů",
|
||||
"Instructions": "Instrukce",
|
||||
"Unrated": "Nehodnocené",
|
||||
"Automate": "Automatizovat",
|
||||
"Empty": "Prázdné",
|
||||
"Key_Ctrl": "Ctrl",
|
||||
"Key_Shift": "Shift",
|
||||
"Time": "Čas",
|
||||
"Text": "Text",
|
||||
"Shopping_list": "Nákupní seznam",
|
||||
"Added_by": "Přidáno uživatelem",
|
||||
"Added_on": "",
|
||||
"AddToShopping": "",
|
||||
"IngredientInShopping": "",
|
||||
"NotInShopping": "",
|
||||
"OnHand": "",
|
||||
"FoodOnHand": "",
|
||||
"FoodNotOnHand": "",
|
||||
"Undefined": "",
|
||||
"Create_Meal_Plan_Entry": "",
|
||||
"Edit_Meal_Plan_Entry": "",
|
||||
"Title": "",
|
||||
"Week": "",
|
||||
"Month": "",
|
||||
"Year": "",
|
||||
"Planner": "",
|
||||
"Planner_Settings": "",
|
||||
"Period": "",
|
||||
"Plan_Period_To_Show": "",
|
||||
"Periods": "",
|
||||
"Plan_Show_How_Many_Periods": "",
|
||||
"Starting_Day": "",
|
||||
"Meal_Types": "",
|
||||
"Meal_Type": "",
|
||||
"New_Entry": "",
|
||||
"Clone": "",
|
||||
"Drag_Here_To_Delete": "",
|
||||
"Meal_Type_Required": "",
|
||||
"Title_or_Recipe_Required": "",
|
||||
"Color": "",
|
||||
"New_Meal_Type": "",
|
||||
"Use_Fractions": "",
|
||||
"Use_Fractions_Help": "",
|
||||
"AddFoodToShopping": "",
|
||||
"RemoveFoodFromShopping": "",
|
||||
"DeleteShoppingConfirm": "",
|
||||
"AddToShopping": "Přidat do nákupního seznamu",
|
||||
"IngredientInShopping": "Tato ingredience je na vašem nákupním seznamu.",
|
||||
"NotInShopping": "{food} není na vašem nákupním seznamu.",
|
||||
"OnHand": "Momentálně k dispozici",
|
||||
"FoodOnHand": "{food} máte k dispozici.",
|
||||
"FoodNotOnHand": "Nemáte {food} k dispozici.",
|
||||
"Undefined": "Neurčeno",
|
||||
"Create_Meal_Plan_Entry": "Vytvořit položku v jídelníčku",
|
||||
"Edit_Meal_Plan_Entry": "Upravit položku v jídelníčku",
|
||||
"Title": "Název",
|
||||
"Week": "Týden",
|
||||
"Month": "Měsíc",
|
||||
"Year": "Rok",
|
||||
"Planner": "Plánovač",
|
||||
"Planner_Settings": "Nastavení plánovače",
|
||||
"Period": "Období",
|
||||
"Plan_Period_To_Show": "Zobrazit týdny, měsíce nebo roky",
|
||||
"Periods": "Období",
|
||||
"Plan_Show_How_Many_Periods": "Kolik období bude zobrazeno",
|
||||
"Starting_Day": "První den v týdnu",
|
||||
"Meal_Types": "Druhy jídel",
|
||||
"Meal_Type": "Druh jídla",
|
||||
"New_Entry": "Nová položka",
|
||||
"Clone": "Klonovat",
|
||||
"Drag_Here_To_Delete": "Přesunutím sem smazat",
|
||||
"Meal_Type_Required": "Druh jídla je povinný",
|
||||
"Title_or_Recipe_Required": "Je požadován název nebo výběr receptu",
|
||||
"Color": "Barva",
|
||||
"New_Meal_Type": "Nový druh jídla",
|
||||
"Use_Fractions": "Použít zlomky",
|
||||
"Use_Fractions_Help": "Automaticky převézt desetinná čísla na zlomky při prohlížení repetu.",
|
||||
"AddFoodToShopping": "Přidat {food} na váš nákupní seznam",
|
||||
"RemoveFoodFromShopping": "Odstranit {food} z nákupního seznamu",
|
||||
"DeleteShoppingConfirm": "Jste si jistí, že chcete odstranit všechno {food} z nákupního seznamu?",
|
||||
"IgnoredFood": "",
|
||||
"Add_Servings_to_Shopping": "",
|
||||
"Week_Numbers": "",
|
||||
"Show_Week_Numbers": "",
|
||||
"Export_As_ICal": "",
|
||||
"Export_To_ICal": "",
|
||||
"Cannot_Add_Notes_To_Shopping": "",
|
||||
"Added_To_Shopping_List": "",
|
||||
"Shopping_List_Empty": "",
|
||||
"Next_Period": "",
|
||||
"Previous_Period": "",
|
||||
"Current_Period": "",
|
||||
"Next_Day": "",
|
||||
"Previous_Day": "",
|
||||
"Add_Servings_to_Shopping": "Přidat {servings} porce na nákupní seznam",
|
||||
"Week_Numbers": "Číslo týdne",
|
||||
"Show_Week_Numbers": "Zobrazit čísla týdnů?",
|
||||
"Export_As_ICal": "Exportovat současný úsek do formátu iCal",
|
||||
"Export_To_ICal": "Export ovat .ics",
|
||||
"Cannot_Add_Notes_To_Shopping": "Poznámky nemohou být přidány na nákupní seznam",
|
||||
"Added_To_Shopping_List": "Přidáno na nákupní seznam",
|
||||
"Shopping_List_Empty": "Váš nákupní seznam je momentálně prázdný, můžete přidat položky pomocí kontextového menu záznamu v jídelníčku (pravým kliknutím na kartu nebo levým kliknutím na ikonu menu)",
|
||||
"Next_Period": "Další období",
|
||||
"Previous_Period": "Předchozí období",
|
||||
"Current_Period": "Současné období",
|
||||
"Next_Day": "Následující den",
|
||||
"Previous_Day": "Předchozí den",
|
||||
"Inherit": "",
|
||||
"InheritFields": "",
|
||||
"FoodInherit": "",
|
||||
"ShowUncategorizedFood": "",
|
||||
"GroupBy": "",
|
||||
"Language": "",
|
||||
"Theme": "",
|
||||
"ShowUncategorizedFood": "Zobrazit nedefinované",
|
||||
"GroupBy": "Seskupit podle",
|
||||
"Language": "Jazyk",
|
||||
"Theme": "Téma",
|
||||
"SupermarketCategoriesOnly": "",
|
||||
"MoveCategory": "",
|
||||
"CountMore": "",
|
||||
"IgnoreThis": "",
|
||||
"DelayFor": "",
|
||||
"Warning": "",
|
||||
"NoCategory": "",
|
||||
"MoveCategory": "Předunout do: ",
|
||||
"CountMore": "...+{count} víc",
|
||||
"IgnoreThis": "Nikdy automaticky nepřídávat {food} na nákupní seznam",
|
||||
"DelayFor": "Odložit na {hours} hodin",
|
||||
"Warning": "Varování",
|
||||
"NoCategory": "Není vybrána žádná kategorie.",
|
||||
"InheritWarning": "",
|
||||
"ShowDelayed": "",
|
||||
"Completed": "",
|
||||
"OfflineAlert": "",
|
||||
"shopping_share": "",
|
||||
"shopping_auto_sync": "",
|
||||
"one_url_per_line": "",
|
||||
"mealplan_autoadd_shopping": "",
|
||||
"mealplan_autoexclude_onhand": "",
|
||||
"mealplan_autoinclude_related": "",
|
||||
"default_delay": "",
|
||||
"plan_share_desc": "",
|
||||
"shopping_share_desc": "",
|
||||
"shopping_auto_sync_desc": "",
|
||||
"mealplan_autoadd_shopping_desc": "",
|
||||
"mealplan_autoexclude_onhand_desc": "",
|
||||
"mealplan_autoinclude_related_desc": "",
|
||||
"default_delay_desc": "",
|
||||
"ShowDelayed": "Zobrazit odložené položky",
|
||||
"Completed": "Dokončeno",
|
||||
"OfflineAlert": "Jste offline, nákupní seznam nemusí být synchronizován.",
|
||||
"shopping_share": "Sdílet nákupní seznam",
|
||||
"shopping_auto_sync": "Automatická synchronizace",
|
||||
"one_url_per_line": "Jeden URL odkaz na řádek",
|
||||
"mealplan_autoadd_shopping": "Automaticky přidat jídelníček",
|
||||
"mealplan_autoexclude_onhand": "Nezahrnovat jídlo k dispozici",
|
||||
"mealplan_autoinclude_related": "Přidat podobné recepty",
|
||||
"default_delay": "Výchozí doba odložení v hodinách",
|
||||
"plan_share_desc": "Nové položky v jídelníčku budou automaticky sdíleny s vybranými uživateli.",
|
||||
"shopping_share_desc": "Uživatelé uvidí všechny položky na vašem nákupním seznamu. Abyste viděli položky na jejich seznamu, musí si přidat vás.",
|
||||
"shopping_auto_sync_desc": "Nastavením 0 dojde k vypnutí automatické synchronizace. Při prohlížení nákupního seznamu je vždy po uplynutí nastaveného počtu vteřin aktualizován o změny, které mohli provést jiní uživatelé. To je užitečné, pokud nakupujete ve více lidech, ale může používat více dat.",
|
||||
"mealplan_autoadd_shopping_desc": "Automaticky podle jídelníčku přidat ingredience na nákupní seznam.",
|
||||
"mealplan_autoexclude_onhand_desc": "Nepřidávat ingredience, které jsou k dispozici, na nákupní seznam, když je vytvořen podle jídelníčku (manuálně nebo automaticky).",
|
||||
"mealplan_autoinclude_related_desc": "Když je nákupní seznam vytvořen podle jídelníčku, přidat i položky z přidružených receptů.",
|
||||
"default_delay_desc": "Výchozí odložení položek v nákupním seznamu v hodinách.",
|
||||
"filter_to_supermarket": "",
|
||||
"Coming_Soon": "",
|
||||
"Auto_Planner": "",
|
||||
"New_Cookbook": "",
|
||||
"Hide_Keyword": "",
|
||||
"Hour": "",
|
||||
"Hours": "",
|
||||
"Day": "",
|
||||
"Days": "",
|
||||
"Second": "",
|
||||
"Seconds": "",
|
||||
"Clear": "",
|
||||
"Users": "",
|
||||
"Invites": "",
|
||||
"err_move_self": "",
|
||||
"nothing": "",
|
||||
"err_merge_self": "",
|
||||
"show_sql": "",
|
||||
"filter_to_supermarket_desc": "",
|
||||
"CategoryName": "",
|
||||
"SupermarketName": "",
|
||||
"CategoryInstruction": "",
|
||||
"Coming_Soon": "Již brzy",
|
||||
"Auto_Planner": "Automatický plánovač",
|
||||
"New_Cookbook": "Nová kuchařka",
|
||||
"Hide_Keyword": "Skrýt klíčová slova",
|
||||
"Hour": "Hodina",
|
||||
"Hours": "Hodiny",
|
||||
"Day": "Den",
|
||||
"Days": "Dny",
|
||||
"Second": "Vteřina",
|
||||
"Seconds": "Vteřiny",
|
||||
"Clear": "Vyčistit",
|
||||
"Users": "Uživatelé",
|
||||
"Invites": "Pozvánky",
|
||||
"err_move_self": "Není možné přesunout jednu položku do sebe samé",
|
||||
"nothing": "Není co dělat",
|
||||
"err_merge_self": "Není možné sloučit položku samu se sebou",
|
||||
"show_sql": "Zobrazit SQL",
|
||||
"filter_to_supermarket_desc": "Standartně zobrazovat položky v nákupním seznamu pouze pro vybraný obchod.",
|
||||
"CategoryName": "Název kategorie",
|
||||
"SupermarketName": "Název obchodu",
|
||||
"CategoryInstruction": "Přetáhnutím kategorií změníte pořadí, ve kterém se zobrazují v nákupním seznamu.",
|
||||
"shopping_recent_days_desc": "",
|
||||
"shopping_recent_days": "",
|
||||
"download_pdf": "",
|
||||
"download_csv": "",
|
||||
"csv_delim_help": "",
|
||||
"csv_delim_label": "",
|
||||
"SuccessClipboard": "",
|
||||
"copy_to_clipboard": "",
|
||||
"shopping_recent_days": "Nedávné dny",
|
||||
"download_pdf": "Stáhnout PDF",
|
||||
"download_csv": "Stáhnout CSV",
|
||||
"csv_delim_help": "Který znak bude použit pro oddělení záznamů v CSV.",
|
||||
"csv_delim_label": "Oddělovač záznamů v CSV",
|
||||
"SuccessClipboard": "Nákupní seznam byl zkopírován do schránky",
|
||||
"copy_to_clipboard": "Zkopírovat do schránky",
|
||||
"csv_prefix_help": "",
|
||||
"csv_prefix_label": "",
|
||||
"copy_markdown_table": "",
|
||||
"in_shopping": "",
|
||||
"DelayUntil": "",
|
||||
"Pin": "",
|
||||
"Unpin": "",
|
||||
"PinnedConfirmation": "",
|
||||
"UnpinnedConfirmation": "",
|
||||
"mark_complete": "",
|
||||
"QuickEntry": "",
|
||||
"shopping_add_onhand_desc": "",
|
||||
"shopping_add_onhand": "",
|
||||
"related_recipes": "",
|
||||
"today_recipes": "",
|
||||
"sql_debug": "",
|
||||
"remember_search": "",
|
||||
"remember_hours": "",
|
||||
"tree_select": "",
|
||||
"OnHand_help": "",
|
||||
"ignore_shopping_help": "",
|
||||
"shopping_category_help": "",
|
||||
"copy_markdown_table": "Kopírovat jako Markdown tabulku",
|
||||
"in_shopping": "V nákupním seznamu",
|
||||
"DelayUntil": "Odložit do",
|
||||
"Pin": "Připnout",
|
||||
"Unpin": "Odepnout",
|
||||
"PinnedConfirmation": "{recipe} byl připnut.",
|
||||
"UnpinnedConfirmation": "{recipe} byl odepnut.",
|
||||
"mark_complete": "Označit jako hotové",
|
||||
"QuickEntry": "Rychlý záznam",
|
||||
"shopping_add_onhand_desc": "Označit potravinu jako \"K dispozici\" když je odškrtnuta na nákupním seznamu.",
|
||||
"shopping_add_onhand": "Automaticky K dispozici",
|
||||
"related_recipes": "Související recepty",
|
||||
"today_recipes": "Dnešní recepty",
|
||||
"sql_debug": "SQL Debug",
|
||||
"remember_search": "Pamatovat vyhledávání",
|
||||
"remember_hours": "Kolik hodin pamatovat",
|
||||
"tree_select": "Použít stromový výběr",
|
||||
"OnHand_help": "Potravina je v inventáři a nebude automaticky přidána na nákupní seznam. Status \"k dipozici\" je sdílen s nakupujícími uživateli.",
|
||||
"ignore_shopping_help": "Nikdy nepřidávat potravinu na nákupní seznam (např. voda)",
|
||||
"shopping_category_help": "Obchody mohou být seřazeny a třízeny pomocí nákupních kategorií podle rozvržení uliček a regálů.",
|
||||
"food_recipe_help": "",
|
||||
"Foods": "",
|
||||
"Account": "",
|
||||
"Cosmetic": "",
|
||||
"Foods": "Potraviny",
|
||||
"Account": "Účet",
|
||||
"Cosmetic": "Zobrazení",
|
||||
"API": "API",
|
||||
"enable_expert": "",
|
||||
"expert_mode": "",
|
||||
"simple_mode": "",
|
||||
"advanced": "",
|
||||
"fields": "",
|
||||
"show_keywords": "",
|
||||
"show_foods": "",
|
||||
"show_books": "",
|
||||
"show_rating": "",
|
||||
"show_units": "",
|
||||
"show_filters": "",
|
||||
"not": "",
|
||||
"save_filter": "",
|
||||
"filter_name": "",
|
||||
"left_handed": "",
|
||||
"left_handed_help": "",
|
||||
"Custom Filter": "",
|
||||
"shared_with": "",
|
||||
"sort_by": "",
|
||||
"enable_expert": "Povolit Expertní režim",
|
||||
"expert_mode": "Expertní režim",
|
||||
"simple_mode": "Jednoduchý režim",
|
||||
"advanced": "Pokročilé",
|
||||
"fields": "Pole",
|
||||
"show_keywords": "Zobrazit klíčová slova",
|
||||
"show_foods": "Zobrazit potraviny",
|
||||
"show_books": "Zobrazit kuchařky",
|
||||
"show_rating": "Zobrazit hodnocení",
|
||||
"show_units": "Zobrazit jednotky",
|
||||
"show_filters": "Zobrazit filtry",
|
||||
"not": "ne",
|
||||
"save_filter": "Uložit filtr",
|
||||
"filter_name": "Název filtru",
|
||||
"left_handed": "Režim pro leváky",
|
||||
"left_handed_help": "Optimalizuje uživatelské prostředí pro levou ruku.",
|
||||
"Custom Filter": "Uživatelský filtr",
|
||||
"shared_with": "Sdíleno s",
|
||||
"sort_by": "Seřadit podle",
|
||||
"asc": "Vzestupně",
|
||||
"desc": "Sestupně",
|
||||
"date_viewed": "",
|
||||
"last_cooked": "",
|
||||
"times_cooked": "",
|
||||
"date_created": "",
|
||||
"show_sortby": "",
|
||||
"date_viewed": "Poslední prohlížené",
|
||||
"last_cooked": "Naposledy vařeno",
|
||||
"times_cooked": "Kolkrát vařeno",
|
||||
"date_created": "Datum vytvoření",
|
||||
"show_sortby": "Zobrazit Seřazeno podle",
|
||||
"search_rank": "",
|
||||
"make_now": "",
|
||||
"recipe_filter": "Filtrovat recepty",
|
||||
"book_filter_help": "",
|
||||
"review_shopping": "",
|
||||
"book_filter_help": "Zahrnout i recepty z filtru stejně jako manuálně přidané.",
|
||||
"review_shopping": "Zkontrolovat nákupní položky před uložením",
|
||||
"view_recipe": "Zobrazit recept",
|
||||
"copy_to_new": "",
|
||||
"copy_to_new": "Zkopírovat do nového receptu",
|
||||
"recipe_name": "Název receptu",
|
||||
"paste_ingredients_placeholder": "",
|
||||
"paste_ingredients": "",
|
||||
"ingredient_list": "",
|
||||
"explain": "",
|
||||
"paste_ingredients_placeholder": "Zde vložit seznam ingrediencí.",
|
||||
"paste_ingredients": "Vložit ingredince",
|
||||
"ingredient_list": "Seznam ingrediencí",
|
||||
"explain": "Vysvětlit",
|
||||
"filter": "Filtr",
|
||||
"Website": "Web",
|
||||
"App": "Aplikace",
|
||||
"Message": "",
|
||||
"Bookmarklet": "",
|
||||
"Sticky_Nav": "",
|
||||
"Sticky_Nav_Help": "",
|
||||
"Nav_Color": "",
|
||||
"Nav_Color_Help": "",
|
||||
"Message": "Zpráva",
|
||||
"Bookmarklet": "Bookmarklet",
|
||||
"Sticky_Nav": "Připnout navigační panel",
|
||||
"Sticky_Nav_Help": "Vždy zobrazit navigační panel na vrchu stránky.",
|
||||
"Nav_Color": "Barva navigačního panelu",
|
||||
"Nav_Color_Help": "Zmenit barvu navigačního panelu.",
|
||||
"Use_Kj": "Používat kJ místo kcal",
|
||||
"Comments_setting": "Zobrazit komentáře",
|
||||
"click_image_import": "Vyberte obrázek, který chcete přiřadit k tomuto receptu",
|
||||
"no_more_images_found": "Žádné další obrázky na zadaném odkazu.",
|
||||
"import_duplicates": "",
|
||||
"paste_json": "",
|
||||
"Click_To_Edit": "",
|
||||
"search_no_recipes": "",
|
||||
"search_import_help_text": "",
|
||||
"search_create_help_text": "",
|
||||
"warning_duplicate_filter": "",
|
||||
"import_duplicates": "Aby bylo zamezeno duplicitním receptům, recepty se stejným jménem jako již existující jsou ignorovány. Pokud chcete přidat všechno, zaškrtněte toto políčko.",
|
||||
"paste_json": "Sem zkopírujte zdroj ve formátu json nebo html.",
|
||||
"Click_To_Edit": "Kliknutím editovat",
|
||||
"search_no_recipes": "Nebyly nealezeny žádné recepty!",
|
||||
"search_import_help_text": "Importovat recept z externí webové stránky nebo aplikace.",
|
||||
"search_create_help_text": "Vytvořit nový recept přímo v Tandoor.",
|
||||
"warning_duplicate_filter": "Varování: Kvůli technickým omezení může použití několika filtrů se stejnou kombinací (a/nebo/ne) přinést neočekávaný výsledek.",
|
||||
"reset_children": "",
|
||||
"reset_children_help": "",
|
||||
"reset_food_inheritance": "",
|
||||
"reset_food_inheritance_info": "",
|
||||
"substitute_help": "",
|
||||
"substitute_siblings_help": "",
|
||||
"substitute_children_help": "",
|
||||
"substitute_help": "Při hledání podle ingrediencí, které jsou k dispozici, jsou zvažovány náhrady.",
|
||||
"substitute_siblings_help": "Všechny potraviny, které sdílejí nadřazenou položku jsou považovány za náhrady.",
|
||||
"substitute_children_help": "Všechny potraviny, které jsou podřízeny této, jsou považovány za náhražky.",
|
||||
"substitute_siblings": "",
|
||||
"substitute_children": "",
|
||||
"SubstituteOnHand": "",
|
||||
"SubstituteOnHand": "Máte k dispozici náhradu.",
|
||||
"ChildInheritFields": "",
|
||||
"ChildInheritFields_help": "",
|
||||
"InheritFields_help": "",
|
||||
@@ -478,5 +478,21 @@
|
||||
"Use_Plural_Food_Simple": "",
|
||||
"plural_usage_info": "",
|
||||
"Create Recipe": "Vytvořit recept",
|
||||
"Import Recipe": "Importovat recept"
|
||||
"Import Recipe": "Importovat recept",
|
||||
"per_serving": "na porci",
|
||||
"open_data_help_text": "Projekt Tandoor Open Data nabízí komunitou poskytnutá data pro Tandoor. Toto pole je automaticky vyplněno při importu a může být později upraveno.",
|
||||
"Data_Import_Info": "Rozšiřte svůj prostor o seznamy jídel, jednotek a další spravované komunitou, a vylepšete tak svoji sbírku receptů.",
|
||||
"Update_Existing_Data": "Aktualizovat existující data",
|
||||
"Use_Metric": "Používat metrické jednotky",
|
||||
"Learn_More": "Zjistit víc",
|
||||
"converted_unit": "Převedená jendotka",
|
||||
"converted_amount": "Převedené množství",
|
||||
"base_unit": "Základní jednotka",
|
||||
"base_amount": "Základní množství",
|
||||
"Datatype": "Datový typ",
|
||||
"Number of Objects": "Počet Objektů",
|
||||
"Property": "Vlastnost",
|
||||
"Conversion": "Převod",
|
||||
"Properties": "Vlastnosti",
|
||||
"recipe_property_info": "Můžete také přidávat vlastnosti k Vašim jídlům. Hodnoty budou automaticky přepočteny na základě Vašeho receptu!"
|
||||
}
|
||||
|
||||
@@ -258,12 +258,14 @@ export class Models {
|
||||
field: "description",
|
||||
label: "Description",
|
||||
placeholder: "",
|
||||
optional: true,
|
||||
},
|
||||
icon: {
|
||||
form_field: true,
|
||||
type: "emoji",
|
||||
field: "icon",
|
||||
label: "Icon",
|
||||
optional: true,
|
||||
},
|
||||
full_name: {
|
||||
form_field: true,
|
||||
@@ -295,6 +297,7 @@ export class Models {
|
||||
field: "plural_name",
|
||||
label: "Plural name",
|
||||
placeholder: "",
|
||||
optional: true,
|
||||
},
|
||||
description: {
|
||||
form_field: true,
|
||||
@@ -302,6 +305,7 @@ export class Models {
|
||||
field: "description",
|
||||
label: "Description",
|
||||
placeholder: "",
|
||||
optional: true,
|
||||
},
|
||||
open_data_slug: {
|
||||
form_field: true,
|
||||
@@ -310,6 +314,7 @@ export class Models {
|
||||
disabled: true,
|
||||
label: "Open_Data_Slug",
|
||||
help_text: "open_data_help_text",
|
||||
optional: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -364,12 +369,14 @@ export class Models {
|
||||
field: "description",
|
||||
label: "Description",
|
||||
placeholder: "",
|
||||
optional: true,
|
||||
},
|
||||
icon: {
|
||||
form_field: true,
|
||||
type: "emoji",
|
||||
field: "icon",
|
||||
label: "Icon",
|
||||
optional: true,
|
||||
},
|
||||
filter: {
|
||||
form_field: true,
|
||||
@@ -377,6 +384,7 @@ export class Models {
|
||||
field: "filter",
|
||||
label: "Custom Filter",
|
||||
list: "CUSTOM_FILTER",
|
||||
optional: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -401,6 +409,7 @@ export class Models {
|
||||
field: "description",
|
||||
label: "Description",
|
||||
placeholder: "",
|
||||
optional: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -451,6 +460,7 @@ export class Models {
|
||||
field: "description",
|
||||
label: "Description",
|
||||
placeholder: "",
|
||||
optional: true,
|
||||
},
|
||||
categories: {
|
||||
form_field: true,
|
||||
@@ -461,6 +471,7 @@ export class Models {
|
||||
field: "category_to_supermarket",
|
||||
label: "Categories", // form.label always translated in utils.getForm()
|
||||
placeholder: "",
|
||||
optional: true,
|
||||
},
|
||||
open_data_slug: {
|
||||
form_field: true,
|
||||
@@ -469,6 +480,7 @@ export class Models {
|
||||
disabled: true,
|
||||
label: "Open_Data_Slug",
|
||||
help_text: "open_data_help_text",
|
||||
optional: true,
|
||||
},
|
||||
},
|
||||
config: {
|
||||
@@ -507,6 +519,7 @@ export class Models {
|
||||
field: "description",
|
||||
label: "Description",
|
||||
placeholder: "",
|
||||
optional: true,
|
||||
},
|
||||
type: {
|
||||
form_field: true,
|
||||
@@ -652,6 +665,7 @@ export class Models {
|
||||
disabled: true,
|
||||
label: "Open_Data_Slug",
|
||||
help_text: "open_data_help_text",
|
||||
optional: true,
|
||||
},
|
||||
|
||||
},
|
||||
@@ -685,6 +699,7 @@ export class Models {
|
||||
field: "icon",
|
||||
label: "Icon",
|
||||
placeholder: "",
|
||||
optional: true,
|
||||
},
|
||||
unit: {
|
||||
form_field: true,
|
||||
@@ -692,6 +707,7 @@ export class Models {
|
||||
field: "unit",
|
||||
label: "Unit",
|
||||
placeholder: "",
|
||||
optional: true,
|
||||
},
|
||||
description: {
|
||||
form_field: true,
|
||||
@@ -699,6 +715,7 @@ export class Models {
|
||||
field: "description",
|
||||
label: "Description",
|
||||
placeholder: "",
|
||||
optional: true,
|
||||
},
|
||||
open_data_slug: {
|
||||
form_field: true,
|
||||
@@ -707,6 +724,7 @@ export class Models {
|
||||
disabled: true,
|
||||
label: "Open_Data_Slug",
|
||||
help_text: "open_data_help_text",
|
||||
optional: true,
|
||||
},
|
||||
},
|
||||
|
||||
@@ -853,15 +871,8 @@ export class Models {
|
||||
apiName: "InviteLink",
|
||||
paginated: false,
|
||||
create: {
|
||||
params: [["email", "group", "valid_until", "reusable"]],
|
||||
params: [["email", "group", "valid_until", "reusable", "internal_note"]],
|
||||
form: {
|
||||
email: {
|
||||
form_field: true,
|
||||
type: "text",
|
||||
field: "email",
|
||||
label: "Email",
|
||||
placeholder: "",
|
||||
},
|
||||
group: {
|
||||
form_field: true,
|
||||
type: "lookup",
|
||||
@@ -878,6 +889,14 @@ export class Models {
|
||||
label: "Valid Until",
|
||||
placeholder: "",
|
||||
},
|
||||
email: {
|
||||
form_field: true,
|
||||
type: "text",
|
||||
field: "email",
|
||||
label: "Email",
|
||||
placeholder: "",
|
||||
optional: true,
|
||||
},
|
||||
reusable: {
|
||||
form_field: true,
|
||||
type: "checkbox",
|
||||
@@ -886,6 +905,15 @@ export class Models {
|
||||
help_text: "reusable_help_text",
|
||||
placeholder: "",
|
||||
},
|
||||
internal_note: {
|
||||
form_field: true,
|
||||
type: "textarea",
|
||||
field: "internal_note",
|
||||
label: "Note",
|
||||
placeholder: "",
|
||||
optional: true,
|
||||
},
|
||||
form_function: "InviteLinkDefaultValid",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -14,6 +14,7 @@ import {BToast} from "bootstrap-vue"
|
||||
// * */
|
||||
import Vue from "vue"
|
||||
import {Actions, Models} from "./models"
|
||||
import moment from "moment";
|
||||
|
||||
export const ToastMixin = {
|
||||
name: "ToastMixin",
|
||||
@@ -721,6 +722,10 @@ export const formFunctions = {
|
||||
form.fields.filter((x) => x.field === "inherit_fields")[0].value = getUserPreference("food_inherit_default")
|
||||
return form
|
||||
},
|
||||
InviteLinkDefaultValid: function (form){
|
||||
form.fields.filter((x) => x.field === "valid_until")[0].value = moment().add(7, "days").format('yyyy-MM-DD')
|
||||
return form
|
||||
},
|
||||
AutomationOrderDefault: function (form) {
|
||||
if (form.fields.filter((x) => x.field === "order")[0].value === undefined) {
|
||||
form.fields.filter((x) => x.field === "order")[0].value = 1000
|
||||
|
||||
Reference in New Issue
Block a user