Compare commits

...

122 Commits
1.4.6 ... 1.4.8

Author SHA1 Message Date
vabene1111
4378a6b0c7 Merge branch 'develop' 2023-03-14 23:10:37 +01:00
vabene1111
d5ca8e9c96 add FAQ manual setup 2023-03-14 23:05:09 +01:00
vabene1111
bbcf7ba8a7 fixed mealie import no steps but ingredients 2023-03-14 22:58:35 +01:00
vabene1111
f29f77a1d5 fixed ingredient to string plural 2023-03-14 22:50:33 +01:00
vabene1111
a3f8b2272c added notes, yields, times and source url to mealie import 2023-03-14 22:46:50 +01:00
vabene1111
008a61823d added origianl image import to paprika 2023-03-14 22:34:09 +01:00
vabene1111
a60f1a3e92 added section headers to bottom nav create 2023-03-14 22:12:39 +01:00
Amara Ude
ebb6e669e2 Translated using Weblate (Spanish)
Currently translated at 74.1% (356 of 480 strings)

Translation: Tandoor/Recipes Frontend
Translate-URL: http://translate.tandoor.dev/projects/tandoor/recipes-frontend/es/
2023-03-13 06:55:47 +00:00
Amara Ude
fdd61d3caf Translated using Weblate (French)
Currently translated at 95.6% (459 of 480 strings)

Translation: Tandoor/Recipes Frontend
Translate-URL: http://translate.tandoor.dev/projects/tandoor/recipes-frontend/fr/
2023-03-13 06:55:47 +00:00
Jin Zhang
72ac272962 Translated using Weblate (French)
Currently translated at 91.9% (443 of 482 strings)

Translation: Tandoor/Recipes Backend
Translate-URL: http://translate.tandoor.dev/projects/tandoor/recipes-backend/fr/
2023-03-13 06:55:47 +00:00
Amara Ude
4395737cc5 Translated using Weblate (French)
Currently translated at 91.9% (443 of 482 strings)

Translation: Tandoor/Recipes Backend
Translate-URL: http://translate.tandoor.dev/projects/tandoor/recipes-backend/fr/
2023-03-13 06:55:47 +00:00
Amara Ude
f3aef2c10b Translated using Weblate (Spanish)
Currently translated at 56.8% (274 of 482 strings)

Translation: Tandoor/Recipes Backend
Translate-URL: http://translate.tandoor.dev/projects/tandoor/recipes-backend/es/
2023-03-13 06:55:47 +00:00
Jin Zhang
df1b75d88a Translated using Weblate (French)
Currently translated at 95.0% (456 of 480 strings)

Translation: Tandoor/Recipes Frontend
Translate-URL: http://translate.tandoor.dev/projects/tandoor/recipes-frontend/fr/
2023-03-12 02:55:53 +00:00
Feng Zhong
0b5fb69664 Translated using Weblate (Chinese (Traditional))
Currently translated at 17.1% (81 of 471 strings)

Translation: Tandoor/Recipes Backend
Translate-URL: http://translate.tandoor.dev/projects/tandoor/recipes-backend/zh_Hant/
2023-03-12 02:55:47 +00:00
Jin Zhang
ff2a75476b Translated using Weblate (French)
Currently translated at 89.8% (433 of 482 strings)

Translation: Tandoor/Recipes Backend
Translate-URL: http://translate.tandoor.dev/projects/tandoor/recipes-backend/fr/
2023-03-12 02:55:47 +00:00
Tomasz Klimczak
ea515c199c Translated using Weblate (Polish)
Currently translated at 100.0% (480 of 480 strings)

Translation: Tandoor/Recipes Frontend
Translate-URL: http://translate.tandoor.dev/projects/tandoor/recipes-frontend/pl/
2023-03-09 20:55:47 +00:00
Feng Zhong
12f0cdb484 Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (480 of 480 strings)

Translation: Tandoor/Recipes Frontend
Translate-URL: http://translate.tandoor.dev/projects/tandoor/recipes-frontend/zh_Hans/
2023-03-08 04:55:47 +00:00
Feng Zhong
f2cd220e22 Translated using Weblate (Chinese (Traditional))
Currently translated at 5.7% (27 of 471 strings)

Translation: Tandoor/Recipes Backend
Translate-URL: http://translate.tandoor.dev/projects/tandoor/recipes-backend/zh_Hant/
2023-03-08 04:55:47 +00:00
liimee
a0a3629e4c Translated using Weblate (Indonesian)
Currently translated at 30.0% (144 of 480 strings)

Translation: Tandoor/Recipes Frontend
Translate-URL: http://translate.tandoor.dev/projects/tandoor/recipes-frontend/id/
2023-03-06 10:55:48 +00:00
Anders Obro
8263c6b725 Translated using Weblate (Danish)
Currently translated at 100.0% (480 of 480 strings)

Translation: Tandoor/Recipes Frontend
Translate-URL: http://translate.tandoor.dev/projects/tandoor/recipes-frontend/da/
2023-03-06 10:55:48 +00:00
Anders Obro
b8b3620ade Translated using Weblate (Danish)
Currently translated at 100.0% (528 of 528 strings)

Translation: Tandoor/Recipes Backend
Translate-URL: http://translate.tandoor.dev/projects/tandoor/recipes-backend/da/
2023-03-06 10:55:48 +00:00
vabene1111
e55faa02d5 recipe view padding without comments 2023-03-02 16:59:45 +01:00
vabene1111
64efadfc81 added bottom padding for recipe view 2023-02-27 16:43:37 +01:00
vabene1111
fb90eede52 fixed blank meal plan when nothing planned on mobile 2023-02-27 16:41:33 +01:00
Jesse
48fda987fb Translated using Weblate (Dutch)
Currently translated at 100.0% (482 of 482 strings)

Translation: Tandoor/Recipes Backend
Translate-URL: http://translate.tandoor.dev/projects/tandoor/recipes-backend/nl/
2023-02-27 13:55:47 +00:00
bebur
8e85fd57b6 Translated using Weblate (Dutch)
Currently translated at 100.0% (478 of 478 strings)

Translation: Tandoor/Recipes Frontend
Translate-URL: http://translate.tandoor.dev/projects/tandoor/recipes-frontend/nl/
2023-02-26 13:15:31 +00:00
bebur
3f475aed03 Translated using Weblate (Dutch)
Currently translated at 100.0% (478 of 478 strings)

Translation: Tandoor/Recipes Frontend
Translate-URL: http://translate.tandoor.dev/projects/tandoor/recipes-frontend/nl/
2023-02-26 13:15:31 +00:00
Jesse
12a11766d9 Translated using Weblate (Dutch)
Currently translated at 100.0% (478 of 478 strings)

Translation: Tandoor/Recipes Frontend
Translate-URL: http://translate.tandoor.dev/projects/tandoor/recipes-frontend/nl/
2023-02-26 13:15:31 +00:00
吕楪
0e90700ce9 Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (482 of 482 strings)

Translation: Tandoor/Recipes Backend
Translate-URL: http://translate.tandoor.dev/projects/tandoor/recipes-backend/zh_Hans/
2023-02-26 13:15:31 +00:00
vabene1111
b7f202d645 working on dedicated food view 2023-02-25 11:41:25 +01:00
vabene1111
f0f12ca83f removed use_plural space setting
remove because i dont see the need and it was causing issues
2023-02-24 23:32:30 +01:00
vabene1111
b14d8f0051 fixed plural showing in lists where it does not make sense 2023-02-24 23:27:20 +01:00
vabene1111
5fd8c56324 Merge branch 'develop' of https://github.com/TandoorRecipes/recipes into develop 2023-02-24 20:36:06 +01:00
vabene1111
8abef1d8cc improved style 2023-02-24 20:35:54 +01:00
vabene1111
0c8c74c0ac context menu working for mobile mealplan view 2023-02-24 20:24:28 +01:00
vabene1111
0b40414d23 basic context menu for meal plan working 2023-02-24 16:10:16 +01:00
vabene1111
d4b8190f55 increased right/left padding in bottom nav 2023-02-24 11:16:12 +01:00
JFL
0ce7ea0b61 Translated using Weblate (French)
Currently translated at 93.5% (447 of 478 strings)

Translation: Tandoor/Recipes Frontend
Translate-URL: http://translate.tandoor.dev/projects/tandoor/recipes-frontend/fr/
2023-02-24 02:55:47 +00:00
JFL
817c4cb9d6 Translated using Weblate (French)
Currently translated at 87.7% (423 of 482 strings)

Translation: Tandoor/Recipes Backend
Translate-URL: http://translate.tandoor.dev/projects/tandoor/recipes-backend/fr/
2023-02-24 02:55:46 +00:00
Oliver Cervera
9962c849ed Translated using Weblate (Italian)
Currently translated at 97.4% (466 of 478 strings)

Translation: Tandoor/Recipes Frontend
Translate-URL: http://translate.tandoor.dev/projects/tandoor/recipes-frontend/it/
2023-02-20 12:55:48 +00:00
vabene1111
8313dc8abe added padding in recipe search view 2023-02-19 22:15:54 +01:00
vabene1111
2781730778 fixed mess 2023-02-19 21:09:06 +01:00
vabene1111
985e98c699 fixed shopping list meal plan logic 2023-02-19 17:05:39 +01:00
vabene1111
d244af28e3 Merge pull request #2290 from TandoorRecipes/dependabot/pip/pillow-9.4.0
Bump pillow from 9.3.0 to 9.4.0
2023-02-19 16:49:56 +01:00
vabene1111
488ac3b94a Merge pull request #2307 from TandoorRecipes/dependabot/pip/cryptography-39.0.1
Bump cryptography from 38.0.4 to 39.0.1
2023-02-19 16:49:41 +01:00
vabene1111
b49426e35c more styling tweaks 2023-02-19 16:42:00 +01:00
vabene1111
a81bac1193 styling and fixes for mealplan and search plan 2023-02-19 16:37:32 +01:00
vabene1111
7fe80b7a5f more styling of mobile meal plan 2023-02-19 16:05:49 +01:00
vabene1111
a6e3ab2dbe mostly working and somewhat styled mobile plan ui 2023-02-19 15:58:39 +01:00
vabene1111
a4f0f38300 meal plan simple mobile layout 2023-02-19 15:24:51 +01:00
vabene1111
1a5b7244dd improved paddings in search view 2023-02-19 14:46:50 +01:00
vabene1111
dff9f91d4c properly integrated bottom nav 2023-02-19 13:54:16 +01:00
vabene1111
59d1c1dcdc improved bottom nav with slots and more 2023-02-19 10:02:31 +01:00
vabene1111
2cff936b5b improved showing of meal plan and bottom nav widget 2023-02-19 08:50:40 +01:00
vabene1111
d9dc644cb6 fixed meal plan edit id handling 2023-02-19 08:44:36 +01:00
vabene1111
2280d04fd2 search view meal plan working 2023-02-19 08:42:23 +01:00
vabene1111
1c8cb69cf3 wip integrating mealplan edit into search 2023-02-18 22:27:17 +01:00
vabene1111
e33c3789b7 fixed add to shopping when using ingredient headers 2023-02-18 21:56:21 +01:00
vabene1111
8d85800e2f updated store 2023-02-18 21:55:24 +01:00
vabene1111
c08c1d30ad fixed review shopping before save, improved meal plan edit modal independece 2023-02-18 21:55:17 +01:00
vabene1111
3c00e1ecdb made meal plan edit modal mostely independent 2023-02-18 21:15:08 +01:00
vabene1111
83947e31aa properly reactive meal plan store with dict 2023-02-18 19:13:32 +01:00
Joachim Weber
b4f90fbbb3 Translated using Weblate (Portuguese (Brazil))
Currently translated at 5.6% (32 of 562 strings)

Translation: Tandoor/Recipes Backend
Translate-URL: http://translate.tandoor.dev/projects/tandoor/recipes-backend/pt_BR/
2023-02-18 10:55:49 +00:00
Joachim Weber
0f55f91586 Translated using Weblate (Portuguese (Brazil))
Currently translated at 36.1% (173 of 478 strings)

Translation: Tandoor/Recipes Frontend
Translate-URL: http://translate.tandoor.dev/projects/tandoor/recipes-frontend/pt_BR/
2023-02-18 10:55:49 +00:00
Joachim Weber
7d0a9b11a0 Translated using Weblate (German)
Currently translated at 100.0% (478 of 478 strings)

Translation: Tandoor/Recipes Frontend
Translate-URL: http://translate.tandoor.dev/projects/tandoor/recipes-frontend/de/
2023-02-18 10:55:49 +00:00
vabene1111
9167261714 add nav to view 2023-02-17 18:00:43 +01:00
vabene1111
57fae34ff6 playing with bottom nav 2023-02-17 17:02:50 +01:00
vabene1111
961578385d new meal plan widget 2023-02-16 23:38:14 +01:00
vabene1111
0dc6bed7ad prevent user preference store from spamming API requests 2023-02-16 23:21:39 +01:00
vabene1111
c78c615372 Merge branch 'develop' into feature/card_ui_2 2023-02-16 22:51:30 +01:00
vabene1111
04bdec3889 Merge branch 'feature/improved-offline' into develop 2023-02-16 22:51:21 +01:00
vabene1111
6af3d7c98f playing around with better meal plan view 2023-02-16 22:50:48 +01:00
vabene1111
73be817c10 moved context menu and re added descripotion to detailed view 2023-02-16 21:30:30 +01:00
vabene1111
faf78fc254 larger pagination 2023-02-16 20:54:30 +01:00
vabene1111
2c85c370e6 description fade 2023-02-16 20:52:11 +01:00
vabene1111
3a38a095d8 nicer card working 2023-02-16 20:38:40 +01:00
vabene1111
e754b13340 quite nice 2023-02-16 20:23:46 +01:00
vabene1111
900c28caba playing around with the recipe card 2023-02-16 19:10:19 +01:00
vabene1111
c5ce197ed7 test setup done for real 2023-02-16 18:28:50 +01:00
vabene1111
9573ff0932 setup test view 2023-02-16 18:26:26 +01:00
vabene1111
f554963ae7 ugly but working import to my tandoor instance button 2023-02-16 18:16:01 +01:00
dependabot[bot]
961619c156 Bump cryptography from 38.0.4 to 39.0.1
Bumps [cryptography](https://github.com/pyca/cryptography) from 38.0.4 to 39.0.1.
- [Release notes](https://github.com/pyca/cryptography/releases)
- [Changelog](https://github.com/pyca/cryptography/blob/main/CHANGELOG.rst)
- [Commits](https://github.com/pyca/cryptography/compare/38.0.4...39.0.1)

---
updated-dependencies:
- dependency-name: cryptography
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-02-16 17:11:41 +00:00
vabene1111
4ecadab53c Merge branch 'develop' of https://github.com/vabene1111/recipes into develop 2023-02-16 18:00:52 +01:00
vabene1111
744501a65d pass url parmeter to import page 2023-02-16 18:00:48 +01:00
vabene1111
44cc66888b Merge pull request #2293 from TandoorRecipes/dependabot/pip/django-debug-toolbar-3.8.1
Bump django-debug-toolbar from 3.7.0 to 3.8.1
2023-02-16 17:53:42 +01:00
vabene1111
0695909b6c Merge pull request #2291 from TandoorRecipes/dependabot/pip/recipe-scrapers-14.30.0
Bump recipe-scrapers from 14.24.0 to 14.30.0
2023-02-16 17:53:01 +01:00
vabene1111
7a4fa38725 Merge pull request #2319 from TandoorRecipes/dependabot/pip/django-4.1.7
Bump django from 4.1.4 to 4.1.7
2023-02-16 17:52:48 +01:00
vabene1111
9f360d8af6 improve cross instance import 2023-02-16 17:47:03 +01:00
vabene1111
5dad6b8b17 enable cross tandoor importing 2023-02-16 17:32:43 +01:00
dependabot[bot]
5b6df6ed2e Bump django from 4.1.4 to 4.1.7
Bumps [django](https://github.com/django/django) from 4.1.4 to 4.1.7.
- [Release notes](https://github.com/django/django/releases)
- [Commits](https://github.com/django/django/compare/4.1.4...4.1.7)

---
updated-dependencies:
- dependency-name: django
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-02-15 20:18:53 +00:00
vabene1111
82d1a75d80 Merge branch 'develop' 2023-02-12 23:10:08 +01:00
vabene1111
50429207c5 import between tandoor instances WIP 2023-02-12 23:09:30 +01:00
vabene1111
589bc1f1aa fixed open graph tags when attributes are missing 2023-02-12 20:52:52 +01:00
vabene1111
824dcefc1a fixed space delete data 2023-02-12 20:52:30 +01:00
vabene1111
3f8c952237 added open graph meta tags 2023-02-12 18:17:05 +01:00
vabene1111
077db58de0 allow markdown in message of the day 2023-02-12 18:16:58 +01:00
vabene1111
3c527fd112 allow infiinit sharing as space setting 2023-02-12 18:16:43 +01:00
vabene1111
cd1f6ad7b0 added pinia to all app entrypoints 2023-02-12 16:14:15 +01:00
vabene1111
3af7e98216 basic pinia store 2023-02-12 16:06:00 +01:00
vabene1111
cb363d6321 added background sync to shopping list entry checking 2023-02-12 12:56:29 +01:00
vabene1111
39656152d3 fixed disabling shopping auto sync not working 2023-02-12 12:55:26 +01:00
vabene1111
22c88e5269 prevent double loading on import 2023-02-12 08:28:26 +01:00
vabene1111
89550e8345 fixed ingredient editor breaking import 2023-02-12 08:28:16 +01:00
vabene1111
9846c4df18 added support for rezeptsuite.de imports 2023-02-11 17:51:44 +01:00
vabene1111
924d1cb71b improved search food api performance 2023-02-11 16:27:41 +01:00
vabene1111
44236f611e removed unnecessary api calles in MealPlanEditModal 2023-02-11 15:56:11 +01:00
vabene1111
012dea5a0c fixed and improved import ingredient edit 2023-02-11 11:57:52 +01:00
vabene1111
820c9b704f improved servings parser 2023-02-11 09:04:05 +01:00
vabene1111
ed92926ec4 fixed plural import 2023-02-11 09:01:10 +01:00
vertilo
bc560ee76d Translated using Weblate (Ukrainian)
Currently translated at 52.9% (253 of 478 strings)

Translation: Tandoor/Recipes Frontend
Translate-URL: http://translate.tandoor.dev/projects/tandoor/recipes-frontend/uk/
2023-02-10 14:55:46 +00:00
vertilo
b6c4130e4b Translated using Weblate (Ukrainian)
Currently translated at 52.7% (252 of 478 strings)

Translation: Tandoor/Recipes Frontend
Translate-URL: http://translate.tandoor.dev/projects/tandoor/recipes-frontend/uk/
2023-02-09 13:55:15 +00:00
vertilo
b0ca391bb4 Translated using Weblate (Ukrainian)
Currently translated at 0.1% (1 of 528 strings)

Translation: Tandoor/Recipes Backend
Translate-URL: http://translate.tandoor.dev/projects/tandoor/recipes-backend/uk/
2023-02-09 13:55:15 +00:00
Marion Kämpfer
45a6b1d386 Translated using Weblate (French)
Currently translated at 93.5% (447 of 478 strings)

Translation: Tandoor/Recipes Frontend
Translate-URL: http://translate.tandoor.dev/projects/tandoor/recipes-frontend/fr/
2023-02-09 13:55:15 +00:00
Laura
4626ffcbc5 Translated using Weblate (French)
Currently translated at 93.5% (447 of 478 strings)

Translation: Tandoor/Recipes Frontend
Translate-URL: http://translate.tandoor.dev/projects/tandoor/recipes-frontend/fr/
2023-02-09 13:55:14 +00:00
Andreas Ljungberg
c3a9cc94fa Translated using Weblate (Swedish)
Currently translated at 100.0% (478 of 478 strings)

Translation: Tandoor/Recipes Frontend
Translate-URL: http://translate.tandoor.dev/projects/tandoor/recipes-frontend/sv/
2023-02-09 13:55:14 +00:00
Marion Kämpfer
a8eb8bb8d7 Translated using Weblate (German)
Currently translated at 99.7% (477 of 478 strings)

Translation: Tandoor/Recipes Frontend
Translate-URL: http://translate.tandoor.dev/projects/tandoor/recipes-frontend/de/
2023-02-09 13:55:14 +00:00
Marion Kämpfer
b14c9aa68c Translated using Weblate (French)
Currently translated at 87.5% (422 of 482 strings)

Translation: Tandoor/Recipes Backend
Translate-URL: http://translate.tandoor.dev/projects/tandoor/recipes-backend/fr/
2023-02-09 13:55:14 +00:00
Marion Kämpfer
b03db7ad36 Translated using Weblate (German)
Currently translated at 99.5% (480 of 482 strings)

Translation: Tandoor/Recipes Backend
Translate-URL: http://translate.tandoor.dev/projects/tandoor/recipes-backend/de/
2023-02-09 13:55:14 +00:00
Adri
cc706a1195 Translated using Weblate (Italian)
Currently translated at 92.1% (444 of 482 strings)

Translation: Tandoor/Recipes Backend
Translate-URL: http://translate.tandoor.dev/projects/tandoor/recipes-backend/it/
2023-02-05 03:55:47 +00:00
dependabot[bot]
c352bf82dd Bump django-debug-toolbar from 3.7.0 to 3.8.1
Bumps [django-debug-toolbar](https://github.com/jazzband/django-debug-toolbar) from 3.7.0 to 3.8.1.
- [Release notes](https://github.com/jazzband/django-debug-toolbar/releases)
- [Changelog](https://github.com/jazzband/django-debug-toolbar/blob/main/docs/changes.rst)
- [Commits](https://github.com/jazzband/django-debug-toolbar/compare/3.7...3.8.1)

---
updated-dependencies:
- dependency-name: django-debug-toolbar
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-02-01 00:02:03 +00:00
dependabot[bot]
a305527ba2 Bump recipe-scrapers from 14.24.0 to 14.30.0
Bumps [recipe-scrapers](https://github.com/hhursev/recipe-scrapers) from 14.24.0 to 14.30.0.
- [Release notes](https://github.com/hhursev/recipe-scrapers/releases)
- [Commits](https://github.com/hhursev/recipe-scrapers/compare/14.24.0...14.30.0)

---
updated-dependencies:
- dependency-name: recipe-scrapers
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-02-01 00:01:46 +00:00
dependabot[bot]
c0e35e89e9 Bump pillow from 9.3.0 to 9.4.0
Bumps [pillow](https://github.com/python-pillow/Pillow) from 9.3.0 to 9.4.0.
- [Release notes](https://github.com/python-pillow/Pillow/releases)
- [Changelog](https://github.com/python-pillow/Pillow/blob/main/CHANGES.rst)
- [Commits](https://github.com/python-pillow/Pillow/compare/9.3.0...9.4.0)

---
updated-dependencies:
- dependency-name: pillow
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-02-01 00:01:39 +00:00
96 changed files with 2830 additions and 1362 deletions

8
.idea/dictionaries/vaben.xml generated Normal file
View File

@@ -0,0 +1,8 @@
<component name="ProjectDictionaryState">
<dictionary name="vaben">
<words>
<w>pinia</w>
<w>selfhosted</w>
</words>
</dictionary>
</component>

View File

@@ -32,11 +32,11 @@ admin.site.unregister(Group)
@admin.action(description='Delete all data from a space')
def delete_space_action(modeladmin, request, queryset):
for space in queryset:
space.save()
space.safe_delete()
class SpaceAdmin(admin.ModelAdmin):
list_display = ('name', 'created_by', 'max_recipes', 'max_users', 'max_file_storage_mb', 'allow_sharing', 'use_plural')
list_display = ('name', 'created_by', 'max_recipes', 'max_users', 'max_file_storage_mb', 'allow_sharing')
search_fields = ('name', 'created_by__username')
list_filter = ('max_recipes', 'max_users', 'max_file_storage_mb', 'allow_sharing')
date_hierarchy = 'created_at'

View File

@@ -126,6 +126,8 @@ class IngredientParser:
amount = 0
unit = None
note = ''
if x.strip() == '':
return amount, unit, note
did_check_frac = False
end = 0

View File

@@ -123,7 +123,7 @@ def share_link_valid(recipe, share):
return c
if link := ShareLink.objects.filter(recipe=recipe, uuid=share, abuse_blocked=False).first():
if 0 < settings.SHARING_LIMIT < link.request_count:
if 0 < settings.SHARING_LIMIT < link.request_count and not link.space.no_sharing_limit:
return False
link.request_count += 1
link.save()

View File

@@ -322,6 +322,11 @@ def parse_servings_text(servings):
servings = re.sub("\d+", '', servings).strip()
except Exception:
servings = ''
if type(servings) == list:
try:
servings = parse_servings_text(servings[1])
except Exception:
pass
return str(servings)[:32]
@@ -419,3 +424,18 @@ def get_images_from_soup(soup, url):
if 'http' in u:
images.append(u)
return images
def clean_dict(input_dict, key):
if type(input_dict) == dict:
for x in list(input_dict):
if x == key:
del input_dict[x]
elif type(input_dict[x]) == dict:
input_dict[x] = clean_dict(input_dict[x], key)
elif type(input_dict[x]) == list:
temp_list = []
for e in input_dict[x]:
temp_list.append(clean_dict(e, key))
return input_dict

View File

@@ -47,6 +47,8 @@ class RecipeShoppingEditor():
self.mealplan = self._kwargs.get('mealplan', None)
if type(self.mealplan) in [int, float]:
self.mealplan = MealPlan.objects.filter(id=self.mealplan, space=self.space)
if type(self.mealplan) == dict:
self.mealplan = MealPlan.objects.filter(id=self.mealplan['id'], space=self.space).first()
self.id = self._kwargs.get('id', None)
self._shopping_list_recipe = self.get_shopping_list_recipe(self.id, self.created_by, self.space)
@@ -107,7 +109,10 @@ class RecipeShoppingEditor():
self.servings = float(servings)
if mealplan := kwargs.get('mealplan', None):
self.mealplan = mealplan
if type(mealplan) == dict:
self.mealplan = MealPlan.objects.filter(id=mealplan['id'], space=self.space).first()
else:
self.mealplan = mealplan
self.recipe = mealplan.recipe
elif recipe := kwargs.get('recipe', None):
self.recipe = recipe
@@ -310,4 +315,4 @@ class RecipeShoppingEditor():
# )
# # return all shopping list items
# return list_recipe
# return list_recipe

View File

@@ -5,6 +5,7 @@ from zipfile import ZipFile
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, Recipe, Step
@@ -23,41 +24,60 @@ class Mealie(Integration):
name=recipe_json['name'].strip(), description=description,
created_by=self.request.user, internal=True, space=self.request.space)
# TODO parse times (given in PT2H3M )
# @vabene check recipe_url_import.iso_duration_to_minutes I think it does what you are looking for
ingredients_added = False
for s in recipe_json['recipe_instructions']:
step = Step.objects.create(
instruction=s['text'], space=self.request.space,
)
if not ingredients_added:
ingredients_added = True
if len(recipe_json['description'].strip()) > 500:
step.instruction = recipe_json['description'].strip() + '\n\n' + step.instruction
ingredient_parser = IngredientParser(self.request, True)
for ingredient in recipe_json['recipe_ingredient']:
try:
if ingredient['food']:
f = ingredient_parser.get_food(ingredient['food'])
u = ingredient_parser.get_unit(ingredient['unit'])
amount = ingredient['quantity']
note = ingredient['note']
original_text = None
else:
amount, unit, food, note = ingredient_parser.parse(ingredient['note'])
f = ingredient_parser.get_food(food)
u = ingredient_parser.get_unit(unit)
original_text = ingredient['note']
step.ingredients.add(Ingredient.objects.create(
food=f, unit=u, amount=amount, note=note, original_text=original_text, space=self.request.space,
))
except Exception:
pass
step = Step.objects.create(instruction=s['text'], space=self.request.space, )
recipe.steps.add(step)
step = recipe.steps.first()
if not step: # if there is no step in the exported data
step = Step.objects.create(instruction='', space=self.request.space, )
recipe.steps.add(step)
if len(recipe_json['description'].strip()) > 500:
step.instruction = recipe_json['description'].strip() + '\n\n' + step.instruction
ingredient_parser = IngredientParser(self.request, True)
for ingredient in recipe_json['recipe_ingredient']:
try:
if ingredient['food']:
f = ingredient_parser.get_food(ingredient['food'])
u = ingredient_parser.get_unit(ingredient['unit'])
amount = ingredient['quantity']
note = ingredient['note']
original_text = None
else:
amount, unit, food, note = ingredient_parser.parse(ingredient['note'])
f = ingredient_parser.get_food(food)
u = ingredient_parser.get_unit(unit)
original_text = ingredient['note']
step.ingredients.add(Ingredient.objects.create(
food=f, unit=u, amount=amount, note=note, original_text=original_text, space=self.request.space,
))
except Exception:
pass
if 'notes' in recipe_json and len(recipe_json['notes']) > 0:
notes_text = "#### Notes \n\n"
for n in recipe_json['notes']:
notes_text += f'{n["text"]} \n'
step = Step.objects.create(
instruction=notes_text, space=self.request.space,
)
recipe.steps.add(step)
if 'recipe_yield' in recipe_json:
recipe.servings = parse_servings(recipe_json['recipe_yield'])
recipe.servings_text = parse_servings_text(recipe_json['recipe_yield'])
if 'total_time' in recipe_json and recipe_json['total_time'] is not None:
recipe.working_time = parse_time(recipe_json['total_time'])
if 'org_url' in recipe_json:
recipe.source_url = recipe_json['org_url']
recipe.save()
for f in self.files:
if '.zip' in f['name']:
import_zip = ZipFile(f['file'])

View File

@@ -5,6 +5,9 @@ import re
from gettext import gettext as _
from io import BytesIO
import requests
import validators
from cookbook.helper.ingredient_parser import IngredientParser
from cookbook.helper.recipe_url_import import parse_servings, parse_servings_text
from cookbook.integration.integration import Integration
@@ -81,7 +84,14 @@ class Paprika(Integration):
recipe.steps.add(step)
if recipe_json.get("photo_data", None):
self.import_recipe_image(recipe, BytesIO(base64.b64decode(recipe_json['photo_data'])), filetype='.jpeg')
try:
if recipe_json.get("image_url", None):
url = recipe_json.get("image_url", None)
if validators.url(url, public=True):
response = requests.get(url)
self.import_recipe_image(recipe, BytesIO(response.content))
except:
if recipe_json.get("photo_data", None):
self.import_recipe_image(recipe, BytesIO(base64.b64decode(recipe_json['photo_data'])), filetype='.jpeg')
return recipe

View File

@@ -1,3 +1,5 @@
import base64
from io import BytesIO
from xml import etree
from lxml import etree
@@ -5,54 +7,65 @@ from lxml import etree
from cookbook.helper.ingredient_parser import IngredientParser
from cookbook.helper.recipe_url_import import parse_time, parse_servings, parse_servings_text
from cookbook.integration.integration import Integration
from cookbook.models import Ingredient, Recipe, Step
from cookbook.models import Ingredient, Recipe, Step, Keyword
class Rezeptsuitede(Integration):
def split_recipe_file(self, file):
xml_file = etree.parse(file).getroot().getchildren()
recipe_list = xml_file.find('recipe')
return recipe_list
return etree.parse(file).getroot().getchildren()
def get_recipe_from_file(self, file):
recipe_xml = file
recipe = Recipe.objects.create(
name=recipe_xml.find('title').text.strip(),
name=recipe_xml.find('head').attrib['title'].strip(),
created_by=self.request.user, internal=True, space=self.request.space)
if recipe_xml.find('servingtype') is not None and recipe_xml.find('servingtype').text is not None:
recipe.servings = parse_servings(recipe_xml.find('servingtype').text.strip())
recipe.servings_text = parse_servings_text(recipe_xml.find('servingtype').text.strip())
if recipe_xml.find('head').attrib['servingtype']:
recipe.servings = parse_servings(recipe_xml.find('head').attrib['servingtype'].strip())
recipe.servings_text = parse_servings_text(recipe_xml.find('head').attrib['servingtype'].strip())
if recipe_xml.find('description') is not None: # description is a list of <li>'s with text
if len(recipe_xml.find('description')) > 0:
recipe.description = recipe_xml.find('description')[0].text[:512]
if recipe_xml.find('remark') is not None: # description is a list of <li>'s with text
if recipe_xml.find('remark').find('line') is not None:
recipe.description = recipe_xml.find('remark').find('line').text[:512]
for step in recipe_xml.find('step'):
if step.text:
step = Step.objects.create(
instruction=step.text.strip(), space=self.request.space,
)
recipe.steps.add(step)
for prep in recipe_xml.findall('preparation'):
try:
if prep.find('step').text:
step = Step.objects.create(
instruction=prep.find('step').text.strip(), space=self.request.space,
)
recipe.steps.add(step)
except Exception:
pass
ingredient_parser = IngredientParser(self.request, True)
if recipe_xml.find('ingredient'):
if recipe_xml.find('part').find('ingredient') is not None:
ingredient_step = recipe.steps.first()
if ingredient_step is None:
ingredient_step = Step.objects.create(space=self.request.space, instruction='')
for ingredient in recipe_xml.find('ingredient'):
for ingredient in recipe_xml.find('part').findall('ingredient'):
f = ingredient_parser.get_food(ingredient.attrib['item'])
u = ingredient_parser.get_unit(ingredient.attrib['unit'])
ingredient_step.ingredients.add(Ingredient.objects.create(
food=f, unit=u, amount=ingredient.attrib['qty'], original_text=ingredient.text.strip(), space=self.request.space,
))
amount, unit, note = ingredient_parser.parse_amount(ingredient.attrib['qty'])
ingredient_step.ingredients.add(Ingredient.objects.create(food=f, unit=u, amount=amount, space=self.request.space, ))
try:
k, created = Keyword.objects.get_or_create(name=recipe_xml.find('head').find('cat').text.strip(), space=self.request.space)
recipe.keywords.add(k)
except Exception as e:
pass
recipe.save()
try:
self.import_recipe_image(recipe, BytesIO(base64.b64decode(recipe_xml.find('head').find('picbin').text)), filetype='.jpeg')
except:
pass
return recipe
def get_file_from_recipe(self, recipe):

View File

@@ -8,8 +8,8 @@ msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2022-04-29 18:42+0200\n"
"PO-Revision-Date: 2022-08-18 14:32+0000\n"
"Last-Translator: Mathias Rasmussen <math625f@gmail.com>\n"
"PO-Revision-Date: 2023-03-06 10:55+0000\n"
"Last-Translator: Anders Obro <oebro@duck.com>\n"
"Language-Team: Danish <http://translate.tandoor.dev/projects/tandoor/"
"recipes-backend/da/>\n"
"Language: da\n"
@@ -17,7 +17,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
"X-Generator: Weblate 4.10.1\n"
"X-Generator: Weblate 4.15\n"
#: .\cookbook\filters.py:23 .\cookbook\templates\forms\ingredients.html:34
#: .\cookbook\templates\space.html:49 .\cookbook\templates\stats.html:28
@@ -2122,9 +2122,9 @@ msgid ""
"return more results than needed to make sure you find what you are looking "
"for."
msgstr ""
"Find hvad du har brug for selvom opskriften har stavefejl. Kan måske "
"returnere flere resultater end du har brug for, for at være sikker på at du "
"finder hvad du leder efter."
"Find hvad du har brug for, selvom opskriften har stavefejl. Kan måske "
"returnere flere resultater end du har brug for, for at være sikker på, at du "
"finder, hvad du leder efter."
#: .\cookbook\templates\settings.html:182
msgid "This is the default behavior"
@@ -2196,8 +2196,7 @@ msgid ""
"You can sign in to your account using any of the following third party\n"
" accounts:"
msgstr ""
"Du kan logge ind på din konto med enhver af de følgende tredjepartsapps\n"
" kontoer:"
"Du kan logge ind på din konto med enhver af de følgende tredjepartskontoer:"
#: .\cookbook\templates\socialaccount\connections.html:52
msgid ""
@@ -2212,7 +2211,7 @@ msgstr "Tilføj en tredjepartskonto"
#: .\cookbook\templates\socialaccount\signup.html:5
msgid "Signup"
msgstr "Registrering"
msgstr "Registrer"
#: .\cookbook\templates\socialaccount\signup.html:10
#, python-format

View File

@@ -15,16 +15,16 @@ msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2023-01-19 19:14+0100\n"
"PO-Revision-Date: 2022-11-21 19:09+0000\n"
"Last-Translator: Alex <mail@alexpts.dev>\n"
"Language-Team: German <http://translate.tandoor.dev/projects/tandoor/recipes-"
"backend/de/>\n"
"PO-Revision-Date: 2023-02-09 13:55+0000\n"
"Last-Translator: Marion Kämpfer <marion@murphyslantech.de>\n"
"Language-Team: German <http://translate.tandoor.dev/projects/tandoor/"
"recipes-backend/de/>\n"
"Language: de\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
"X-Generator: Weblate 4.14.1\n"
"X-Generator: Weblate 4.15\n"
#: .\cookbook\forms.py:52
msgid "Default unit"
@@ -480,7 +480,7 @@ msgstr "Rezeptanzahl im Suchfiltern anzeigen"
#: .\cookbook\forms.py:541
msgid "Use the plural form for units and food inside this space."
msgstr ""
msgstr "Pluralform für Einheiten und Essen in diesem Space verwenden."
#: .\cookbook\helper\AllAuthCustomAdapter.py:39
msgid ""
@@ -544,7 +544,7 @@ msgstr "Favorit"
#: .\cookbook\integration\copymethat.py:50
msgid "I made this"
msgstr ""
msgstr "Von mir gekocht"
#: .\cookbook\integration\integration.py:223
msgid ""
@@ -1643,7 +1643,7 @@ msgstr "Zurück"
#: .\cookbook\templates\profile.html:7
msgid "Profile"
msgstr ""
msgstr "Profil"
#: .\cookbook\templates\recipe_view.html:26
msgid "by"

View File

@@ -14,8 +14,8 @@ msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2023-01-19 19:14+0100\n"
"PO-Revision-Date: 2022-08-12 21:32+0000\n"
"Last-Translator: Thorin <thorin8@hotmail.com>\n"
"PO-Revision-Date: 2023-03-13 06:55+0000\n"
"Last-Translator: Amara Ude <apu24@drexel.edu>\n"
"Language-Team: Spanish <http://translate.tandoor.dev/projects/tandoor/"
"recipes-backend/es/>\n"
"Language: es\n"
@@ -23,7 +23,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
"X-Generator: Weblate 4.10.1\n"
"X-Generator: Weblate 4.15\n"
#: .\cookbook\forms.py:52
msgid "Default unit"
@@ -143,7 +143,7 @@ msgstr ""
#: .\cookbook\forms.py:84
msgid "Exclude ingredients that are on hand."
msgstr ""
msgstr "Excluir ingredientes que están disponibles."
#: .\cookbook\forms.py:85
msgid "Will optimize the UI for use with your left hand."
@@ -296,36 +296,49 @@ msgid ""
"Use fuzzy matching on units, keywords and ingredients when editing and "
"importing recipes."
msgstr ""
"Utilizar comparación difusa en unidades, palabras clave e ingredientes al "
"editar e importar recetas."
#: .\cookbook\forms.py:446
msgid ""
"Fields to search ignoring accents. Selecting this option can improve or "
"degrade search quality depending on language"
msgstr ""
"Campos de búsqueda ignorando acentos.  La selección de esta opción puede "
"mejorar o degradar la calidad de la búsqueda dependiendo del idioma"
#: .\cookbook\forms.py:448
msgid ""
"Fields to search for partial matches. (e.g. searching for 'Pie' will return "
"'pie' and 'piece' and 'soapie')"
msgstr ""
"Campos de búsqueda para coincidencias parciales. (por ejemplo, buscar 'Pie' "
"devolverá 'pie' y 'piece' y 'soapie')"
#: .\cookbook\forms.py:450
msgid ""
"Fields to search for beginning of word matches. (e.g. searching for 'sa' "
"will return 'salad' and 'sandwich')"
msgstr ""
"Campos de búsqueda para coincidencias al principio de la palabra. (por "
"ejemplo, buscar 'sa' devolverá 'ensalada' y 'sándwich')"
#: .\cookbook\forms.py:452
msgid ""
"Fields to 'fuzzy' search. (e.g. searching for 'recpie' will find 'recipe'.) "
"Note: this option will conflict with 'web' and 'raw' methods of search."
msgstr ""
"Campos para búsqueda \"difusa\". (por ejemplo, buscar 'recpie' encontrará "
"'receta'). Nota: esta opción entrará en conflicto con los métodos de "
"búsqueda 'web' y 'raw'."
#: .\cookbook\forms.py:454
msgid ""
"Fields to full text search. Note: 'web', 'phrase', and 'raw' search methods "
"only function with fulltext fields."
msgstr ""
"Campos para búsqueda de texto completo. Nota: los métodos de búsqueda 'web', "
"'phrase' y 'raw' solo funcionan con campos de texto completo."
#: .\cookbook\forms.py:458
msgid "Search Method"
@@ -333,25 +346,23 @@ msgstr "Método de Búsqueda"
#: .\cookbook\forms.py:459
msgid "Fuzzy Lookups"
msgstr ""
msgstr "Búsquedas difusas"
#: .\cookbook\forms.py:460
msgid "Ignore Accent"
msgstr ""
msgstr "Ignorar Acento"
#: .\cookbook\forms.py:461
msgid "Partial Match"
msgstr ""
msgstr "Coincidencia Parcial"
#: .\cookbook\forms.py:462
msgid "Starts With"
msgstr ""
msgstr "Comienza Con"
#: .\cookbook\forms.py:463
#, fuzzy
#| msgid "Search"
msgid "Fuzzy Search"
msgstr "Buscar"
msgstr "Búsqueda Difusa"
#: .\cookbook\forms.py:464
msgid "Full Text"
@@ -362,42 +373,53 @@ msgid ""
"Users will see all items you add to your shopping list. They must add you "
"to see items on their list."
msgstr ""
"Los usuarios verán todos los elementos que agregues a tu lista de compras. "
"Deben agregarte para ver los elementos en su lista."
#: .\cookbook\forms.py:495
msgid ""
"When adding a meal plan to the shopping list (manually or automatically), "
"include all related recipes."
msgstr ""
"Al agregar un plan de comidas a la lista de compras (manualmente o "
"automáticamente), incluir todas las recetas relacionadas."
#: .\cookbook\forms.py:496
msgid ""
"When adding a meal plan to the shopping list (manually or automatically), "
"exclude ingredients that are on hand."
msgstr ""
"Al agregar un plan de comidas a la lista de compras (manualmente o "
"automáticamente), excluir los ingredientes que están disponibles."
#: .\cookbook\forms.py:497
msgid "Default number of hours to delay a shopping list entry."
msgstr ""
"Número predeterminado de horas para retrasar una entrada en la lista de "
"compras."
#: .\cookbook\forms.py:498
msgid "Filter shopping list to only include supermarket categories."
msgstr ""
"Filtrar la lista de compras para incluir solo categorías de supermercados."
#: .\cookbook\forms.py:499
msgid "Days of recent shopping list entries to display."
msgstr ""
msgstr "Días de entradas recientes en la lista de compras a mostrar."
#: .\cookbook\forms.py:500
msgid "Mark food 'On Hand' when checked off shopping list."
msgstr ""
"Marcar los alimentos como 'Disponible' cuando se marca en la lista de "
"compras."
#: .\cookbook\forms.py:501
msgid "Delimiter to use for CSV exports."
msgstr ""
msgstr "Delimitador a utilizar para exportaciones CSV."
#: .\cookbook\forms.py:502
msgid "Prefix to add when copying list to the clipboard."
msgstr ""
msgstr "Prefijo a agregar al copiar la lista al portapapeles."
#: .\cookbook\forms.py:506
msgid "Share Shopping List"
@@ -405,23 +427,23 @@ msgstr "Compartir Lista de la Compra"
#: .\cookbook\forms.py:507
msgid "Autosync"
msgstr ""
msgstr "Autosincronización"
#: .\cookbook\forms.py:508
msgid "Auto Add Meal Plan"
msgstr ""
msgstr "Agregar Plan de Comidas automáticamente"
#: .\cookbook\forms.py:509
msgid "Exclude On Hand"
msgstr ""
msgstr "Excluir Disponible"
#: .\cookbook\forms.py:510
msgid "Include Related"
msgstr ""
msgstr "Incluir Relacionados"
#: .\cookbook\forms.py:511
msgid "Default Delay Hours"
msgstr ""
msgstr "Horas de Retraso Predeterminadas"
#: .\cookbook\forms.py:512
msgid "Filter to Supermarket"
@@ -429,11 +451,11 @@ msgstr "Filtrar según Supermercado"
#: .\cookbook\forms.py:513
msgid "Recent Days"
msgstr ""
msgstr "Días Recientes"
#: .\cookbook\forms.py:514
msgid "CSV Delimiter"
msgstr ""
msgstr "Delimitador CSV"
#: .\cookbook\forms.py:515
msgid "List Prefix"
@@ -441,21 +463,19 @@ msgstr "Prefijo de la lista"
#: .\cookbook\forms.py:516
msgid "Auto On Hand"
msgstr ""
msgstr "Auto en existencia"
#: .\cookbook\forms.py:526
msgid "Reset Food Inheritance"
msgstr ""
msgstr "Restablecer la herencia de alimentos"
#: .\cookbook\forms.py:527
msgid "Reset all food to inherit the fields configured."
msgstr ""
msgstr "Reiniciar todos los alimentos para heredar los campos configurados."
#: .\cookbook\forms.py:539
#, fuzzy
#| msgid "Food that should be replaced."
msgid "Fields on food that should be inherited by default."
msgstr "Alimento que se va a reemplazar."
msgstr "Campos en los alimentos que deben ser heredados por defecto."
#: .\cookbook\forms.py:540
msgid "Show recipe counts on search filters"
@@ -464,12 +484,15 @@ msgstr "Mostrar cantidad de recetas en los filtros de búsquedas"
#: .\cookbook\forms.py:541
msgid "Use the plural form for units and food inside this space."
msgstr ""
"Utilice la forma plural para las unidades y alimentos dentro de este espacio."
#: .\cookbook\helper\AllAuthCustomAdapter.py:39
msgid ""
"In order to prevent spam, the requested email was not send. Please wait a "
"few minutes and try again."
msgstr ""
"Para prevenir el spam, el correo electrónico solicitado no se envió. Por "
"favor, espere unos minutos e inténtelo de nuevo."
#: .\cookbook\helper\permission_helper.py:164
#: .\cookbook\helper\permission_helper.py:187 .\cookbook\views\views.py:114
@@ -498,7 +521,7 @@ msgstr "¡No puede interactuar con este objeto ya que no es de tu propiedad!"
#: .\cookbook\helper\permission_helper.py:403
msgid "You have reached the maximum number of recipes for your space."
msgstr ""
msgstr "Ha alcanzado el número máximo de recetas para su espacio."
#: .\cookbook\helper\permission_helper.py:415
msgid "You have more users than allowed in your space."

View File

@@ -14,10 +14,10 @@ msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2023-01-19 19:14+0100\n"
"PO-Revision-Date: 2023-01-18 01:55+0000\n"
"Last-Translator: Fall1ngStar <fall1ngstar.public@gmail.com>\n"
"Language-Team: French <http://translate.tandoor.dev/projects/tandoor/recipes-"
"backend/fr/>\n"
"PO-Revision-Date: 2023-03-13 06:55+0000\n"
"Last-Translator: Jin Zhang <JinLZhang278@hotmail.com>\n"
"Language-Team: French <http://translate.tandoor.dev/projects/tandoor/"
"recipes-backend/fr/>\n"
"Language: fr\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
@@ -288,16 +288,12 @@ msgstr ""
"que davantage de fautes de frappe sont ignorées)."
#: .\cookbook\forms.py:443
#, fuzzy
#| msgid ""
#| "Select type method of search. Click <a href=\"/docs/search/\">here</a> "
#| "for full desciption of choices."
msgid ""
"Select type method of search. Click <a href=\"/docs/search/\">here</a> for "
"full description of choices."
msgstr ""
"Sélectionner la méthode de recherche. Cliquer <a href=\"/docs/search/"
"\">ici</a> pour une description complète des choix."
"Sélectionner la méthode de recherche. Cliquer <a href=\"/docs/search/\""
">ici</a> pour une description complète des choix."
#: .\cookbook\forms.py:444
msgid ""
@@ -407,6 +403,8 @@ msgstr ""
#: .\cookbook\forms.py:497
msgid "Default number of hours to delay a shopping list entry."
msgstr ""
"Nombre d'heures par défaut pour retarder l'ajoût d'un article à la liste de "
"courses."
#: .\cookbook\forms.py:498
msgid "Filter shopping list to only include supermarket categories."
@@ -416,7 +414,7 @@ msgstr ""
#: .\cookbook\forms.py:499
msgid "Days of recent shopping list entries to display."
msgstr ""
msgstr "Jours des entrées récentes de la liste de courses à afficher."
#: .\cookbook\forms.py:500
msgid "Mark food 'On Hand' when checked off shopping list."
@@ -453,7 +451,7 @@ msgstr "Inclure recettes connexes"
#: .\cookbook\forms.py:511
msgid "Default Delay Hours"
msgstr ""
msgstr "Heures de retard par défaut"
#: .\cookbook\forms.py:512
msgid "Filter to Supermarket"
@@ -477,17 +475,15 @@ msgstr "Disponible automatique"
#: .\cookbook\forms.py:526
msgid "Reset Food Inheritance"
msgstr ""
msgstr "Réinitialiser l'héritage alimentaire"
#: .\cookbook\forms.py:527
msgid "Reset all food to inherit the fields configured."
msgstr "Réinitialiser tous les aliments pour hériter les champs configurés."
#: .\cookbook\forms.py:539
#, fuzzy
#| msgid "Food that should be replaced."
msgid "Fields on food that should be inherited by default."
msgstr "Aliment qui devrait être remplacé."
msgstr "Champs sur les aliments à hériter par défaut."
#: .\cookbook\forms.py:540
msgid "Show recipe counts on search filters"
@@ -497,6 +493,7 @@ msgstr ""
#: .\cookbook\forms.py:541
msgid "Use the plural form for units and food inside this space."
msgstr ""
"Utiliser la forme plurielle pour les unités et les aliments dans ce groupe."
#: .\cookbook\helper\AllAuthCustomAdapter.py:39
msgid ""
@@ -546,13 +543,11 @@ msgstr ""
#: .\cookbook\helper\recipe_search.py:570
msgid "One of queryset or hash_key must be provided"
msgstr ""
msgstr "Il est nécessaire de fournir soit le queryset, soit la clé de hachage"
#: .\cookbook\helper\shopping_helper.py:152
#, fuzzy
#| msgid "You must supply a created_by"
msgid "You must supply a servings size"
msgstr "Vous devez fournir une information créé_par"
msgstr "Vous devez fournir une information de portion"
#: .\cookbook\helper\template_helper.py:79
#: .\cookbook\helper\template_helper.py:81
@@ -565,8 +560,9 @@ msgid "Favorite"
msgstr "Favori"
#: .\cookbook\integration\copymethat.py:50
#, fuzzy
msgid "I made this"
msgstr ""
msgstr "J'ai fait ça"
#: .\cookbook\integration\integration.py:223
msgid ""
@@ -616,7 +612,7 @@ msgstr "Portions"
#: .\cookbook\integration\saffron.py:25
msgid "Waiting time"
msgstr "Temps dattente"
msgstr "temps dattente"
#: .\cookbook\integration\saffron.py:27
msgid "Preparation Time"
@@ -721,16 +717,12 @@ msgid "Keyword Alias"
msgstr "Mot-clé équivalent"
#: .\cookbook\models.py:1231
#, fuzzy
#| msgid "Description"
msgid "Description Replace"
msgstr "Description"
msgstr "Remplacer la Description"
#: .\cookbook\models.py:1231
#, fuzzy
#| msgid "Instructions"
msgid "Instruction Replace"
msgstr "Instructions"
msgstr "Remplacer l'instruction"
#: .\cookbook\models.py:1257 .\cookbook\views\delete.py:36
#: .\cookbook\views\edit.py:251 .\cookbook\views\new.py:48
@@ -755,7 +747,7 @@ msgstr "Vous avez atteint votre limite de téléversement de fichiers."
#: .\cookbook\serializer.py:291
msgid "Cannot modify Space owner permission."
msgstr ""
msgstr "Impossible de modifier les permissions du propriétaire de groupe."
#: .\cookbook\serializer.py:1085
msgid "Hello"
@@ -804,11 +796,15 @@ msgid ""
"List of ingredient IDs from the recipe to add, if not provided all "
"ingredients will be added."
msgstr ""
"Liste didentifiants dingrédient de la recette à ajouter, si non renseigné, "
"tous les ingrédients seront ajoutés."
#: .\cookbook\serializer.py:1238
msgid ""
"Providing a list_recipe ID and servings of 0 will delete that shopping list."
msgstr ""
"Fournir un identifiant de liste de courses et un nombre de portions de 0 "
"supprimera cette liste de courses."
#: .\cookbook\serializer.py:1247
msgid "Amount of food to add to the shopping list"
@@ -819,8 +815,11 @@ msgid "ID of unit to use for the shopping list"
msgstr "ID de lunité à utiliser pour la liste de courses"
#: .\cookbook\serializer.py:1251
#, fuzzy
msgid "When set to true will delete all food from active shopping lists."
msgstr ""
"Lorsqu'il est défini sur \"true\", tous les aliments des listes de courses "
"actives seront supprimés."
#: .\cookbook\tables.py:61 .\cookbook\tables.py:75
#: .\cookbook\templates\generic\delete_template.html:7
@@ -947,7 +946,7 @@ msgid ""
" <a href=\"%(email_url)s\">issue a new e-mail confirmation "
"request</a>."
msgstr ""
"Ce lien de confirmation reçu par mail est expiré ou invalide. Veuillez\n"
"Ce lien de confirmation reçu par mail est expiré ou non valide. Veuillez\n"
" <a href=\"%(email_url)s\">demander une nouvelle vérification "
"par mail</a>."
@@ -1058,10 +1057,10 @@ msgid ""
" Please request a <a href=\"%(passwd_reset_url)s\">new "
"password reset</a>."
msgstr ""
"Le lien de changement du mot de passe est invalide, probablement parce quil "
"a déjà été utilisé.\n"
" Merci de demander un <a href=\"%(passwd_reset_url)s"
"\">nouveau changement de mot de passe</a>."
"Le lien de changement du mot de passe nest pas valide, probablement parce "
"quil a déjà été utilisé.\n"
" Merci de demander un <a href=\"%(passwd_reset_url)s\""
">nouveau changement de mot de passe</a>."
#: .\cookbook\templates\account\password_reset_from_key.html:33
msgid "change password"
@@ -1172,10 +1171,8 @@ msgstr "Historique"
#: .\cookbook\templates\base.html:255
#: .\cookbook\templates\ingredient_editor.html:7
#: .\cookbook\templates\ingredient_editor.html:13
#, fuzzy
#| msgid "Ingredients"
msgid "Ingredient Editor"
msgstr "Ingrédients"
msgstr "Éditeur dingrédients"
#: .\cookbook\templates\base.html:267
#: .\cookbook\templates\export_response.html:7
@@ -1210,15 +1207,13 @@ msgstr "Admin"
#: .\cookbook\templates\base.html:312
#: .\cookbook\templates\space_overview.html:25
#, fuzzy
#| msgid "No Space"
msgid "Your Spaces"
msgstr "Aucun groupe"
msgstr "Vos groupes"
#: .\cookbook\templates\base.html:323
#: .\cookbook\templates\space_overview.html:6
msgid "Overview"
msgstr ""
msgstr "Aperçu"
#: .\cookbook\templates\base.html:327
msgid "Markdown Guide"
@@ -1242,11 +1237,11 @@ msgstr "Déconnexion"
#: .\cookbook\templates\base.html:360
msgid "You are using the free version of Tandor"
msgstr ""
msgstr "Vous utilisez la version gratuite de Tandoor"
#: .\cookbook\templates\base.html:361
msgid "Upgrade Now"
msgstr ""
msgstr "Mettez à jour maintenant"
#: .\cookbook\templates\batch\edit.html:6
msgid "Batch edit Category"
@@ -1340,8 +1335,9 @@ msgid "Are you sure you want to delete the %(title)s: <b>%(object)s</b> "
msgstr "Êtes-vous sûr(e) de vouloir supprimer %(title)s : <b>%(object)s</b> "
#: .\cookbook\templates\generic\delete_template.html:22
#, fuzzy
msgid "This cannot be undone!"
msgstr ""
msgstr "Cela ne peut pas être annulé !"
#: .\cookbook\templates\generic\delete_template.html:27
msgid "Protected"
@@ -1506,8 +1502,6 @@ msgstr ""
#: .\cookbook\templates\markdown_info.html:57
#: .\cookbook\templates\markdown_info.html:73
#, fuzzy
#| msgid "or by leaving a blank line inbetween."
msgid "or by leaving a blank line in between."
msgstr "ou en laissant une ligne vide entre deux."
@@ -1531,16 +1525,12 @@ msgid "Lists"
msgstr "Listes"
#: .\cookbook\templates\markdown_info.html:85
#, fuzzy
#| msgid ""
#| "Lists can ordered or unorderd. It is <b>important to leave a blank line "
#| "before the list!</b>"
msgid ""
"Lists can ordered or unordered. It is <b>important to leave a blank line "
"before the list!</b>"
msgstr ""
"Les listes peuvent être ordonnées ou non. Il est <b>important de laisser une "
"ligne vide avant la liste !</b>"
"ligne vide avant la liste!</b>"
#: .\cookbook\templates\markdown_info.html:87
#: .\cookbook\templates\markdown_info.html:108
@@ -1667,11 +1657,11 @@ msgstr ""
#: .\cookbook\templates\openid\login.html:27
#: .\cookbook\templates\socialaccount\authentication_error.html:27
msgid "Back"
msgstr ""
msgstr "Retour"
#: .\cookbook\templates\profile.html:7
msgid "Profile"
msgstr ""
msgstr "Profil"
#: .\cookbook\templates\recipe_view.html:26
msgid "by"
@@ -2083,17 +2073,15 @@ msgstr "Créer un compte superutilisateur"
#: .\cookbook\templates\socialaccount\authentication_error.html:7
#: .\cookbook\templates\socialaccount\authentication_error.html:23
#, fuzzy
#| msgid "Social Login"
msgid "Social Network Login Failure"
msgstr "Connexion par réseau social"
msgstr "Échec de la connexion au réseau social"
#: .\cookbook\templates\socialaccount\authentication_error.html:25
#, fuzzy
#| msgid "An error occurred attempting to move "
msgid ""
"An error occurred while attempting to login via your social network account."
msgstr "Une erreur est survenue en essayant de déplacer "
msgstr ""
"Une erreur est survenue en essayant de vous connecter avec votre compte de "
"réseau social."
#: .\cookbook\templates\socialaccount\connections.html:4
#: .\cookbook\templates\socialaccount\connections.html:15
@@ -2131,26 +2119,30 @@ msgstr "Sinscrire"
#: .\cookbook\templates\socialaccount\login.html:9
#, python-format
msgid "Connect %(provider)s"
msgstr ""
msgstr "Connecter %(provider)s"
#: .\cookbook\templates\socialaccount\login.html:11
#, python-format
msgid "You are about to connect a new third party account from %(provider)s."
msgstr ""
"Vous êtes sur le point de connecter un nouveau compte tiers depuis "
"%(provider)s."
#: .\cookbook\templates\socialaccount\login.html:13
#, python-format
msgid "Sign In Via %(provider)s"
msgstr ""
msgstr "Se connecter via %(provider)s"
#: .\cookbook\templates\socialaccount\login.html:15
#, python-format
msgid "You are about to sign in using a third party account from %(provider)s."
msgstr ""
"ous êtes sur le point de vous connecter en utilisant un compte tiers depuis "
"%(provider)s."
#: .\cookbook\templates\socialaccount\login.html:20
msgid "Continue"
msgstr ""
msgstr "Continuer"
#: .\cookbook\templates\socialaccount\signup.html:10
#, python-format
@@ -2190,8 +2182,6 @@ msgid "Manage Subscription"
msgstr "Gérer labonnement"
#: .\cookbook\templates\space_overview.html:13 .\cookbook\views\delete.py:216
#, fuzzy
#| msgid "Space:"
msgid "Space"
msgstr "Groupe :"
@@ -2210,13 +2200,11 @@ msgstr "Vous pouvez être invité dans un groupe existant ou en créer un."
#: .\cookbook\templates\space_overview.html:53
msgid "Owner"
msgstr ""
msgstr "Propriétaire"
#: .\cookbook\templates\space_overview.html:57
#, fuzzy
#| msgid "Create Space"
msgid "Leave Space"
msgstr "Créer un groupe"
msgstr "Quitter le groupe"
#: .\cookbook\templates\space_overview.html:78
#: .\cookbook\templates\space_overview.html:88
@@ -2451,6 +2439,8 @@ msgstr "{obj.name} a été ajouté(e) à la liste de courses."
#: .\cookbook\views\api.py:679
msgid "ID of recipe a step is part of. For multiple repeat parameter."
msgstr ""
"Identifiant de la recette dont fait partie une étape. Pour plusieurs "
"paramètres de répétition."
#: .\cookbook\views\api.py:681
msgid "Query string matched (fuzzy) against object name."
@@ -2606,7 +2596,7 @@ msgstr "Rien à faire."
#: .\cookbook\views\api.py:1180
msgid "Invalid Url"
msgstr ""
msgstr "Url non valide"
#: .\cookbook\views\api.py:1187
msgid "Connection Refused."
@@ -2614,11 +2604,9 @@ msgstr "Connexion refusée."
#: .\cookbook\views\api.py:1192
msgid "Bad URL Schema."
msgstr ""
msgstr "Mauvais schéma dURL."
#: .\cookbook\views\api.py:1215
#, fuzzy
#| msgid "No useable data could be found."
msgid "No usable data could be found."
msgstr "Aucune information utilisable n'a été trouvée."
@@ -2734,10 +2722,8 @@ msgid "Shopping Categories"
msgstr "Catégories de courses"
#: .\cookbook\views\lists.py:187
#, fuzzy
#| msgid "Filter"
msgid "Custom Filters"
msgstr "Filtre"
msgstr "Filtre personnalisé"
#: .\cookbook\views\lists.py:224
msgid "Steps"

View File

@@ -12,8 +12,8 @@ msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2023-01-19 19:14+0100\n"
"PO-Revision-Date: 2023-01-15 16:55+0000\n"
"Last-Translator: Oliver Cervera <olivercervera@yahoo.it>\n"
"PO-Revision-Date: 2023-02-05 03:55+0000\n"
"Last-Translator: Adri <adrian.polimi@gmail.com>\n"
"Language-Team: Italian <http://translate.tandoor.dev/projects/tandoor/"
"recipes-backend/it/>\n"
"Language: it\n"
@@ -285,7 +285,7 @@ msgid ""
"Select type method of search. Click <a href=\"/docs/search/\">here</a> for "
"full description of choices."
msgstr ""
"Seleziona il metodo di ricerca. Clicca <a href=\"/docs/search/\">qui</a> "
"Seleziona il metodo di ricerca. Clicca <a href=\"/docs/search/\">qui</a> "
"per avere maggiori informazioni."
#: .\cookbook\forms.py:444
@@ -334,6 +334,8 @@ msgid ""
"Fields to full text search. Note: 'web', 'phrase', and 'raw' search methods "
"only function with fulltext fields."
msgstr ""
"Campi per la ricerca full-text. Nota: i metodi di ricerca 'web', 'frase' e "
"'raw' funzionano solo con i campi full-text."
#: .\cookbook\forms.py:458
msgid "Search Method"
@@ -462,11 +464,11 @@ msgstr "Disponibilità automatica"
#: .\cookbook\forms.py:526
msgid "Reset Food Inheritance"
msgstr ""
msgstr "Ripristina Eredità Alimenti"
#: .\cookbook\forms.py:527
msgid "Reset all food to inherit the fields configured."
msgstr ""
msgstr "Ripristina tutti gli alimenti per ereditare i campi configurati."
#: .\cookbook\forms.py:539
msgid "Fields on food that should be inherited by default."
@@ -480,6 +482,8 @@ msgstr "Mostra il conteggio delle ricette nei filtri di ricerca"
#: .\cookbook\forms.py:541
msgid "Use the plural form for units and food inside this space."
msgstr ""
"Usare la forma plurale per le unità e gli alimenti all'interno di questo "
"spazio."
#: .\cookbook\helper\AllAuthCustomAdapter.py:39
msgid ""
@@ -542,7 +546,7 @@ msgstr "Preferito"
#: .\cookbook\integration\copymethat.py:50
msgid "I made this"
msgstr ""
msgstr "L'ho preparato"
#: .\cookbook\integration\integration.py:223
msgid ""
@@ -697,16 +701,12 @@ msgid "Keyword Alias"
msgstr "Alias Parola Chiave"
#: .\cookbook\models.py:1231
#, fuzzy
#| msgid "Description"
msgid "Description Replace"
msgstr "Descrizione"
msgstr "Sostituisci Descrizione"
#: .\cookbook\models.py:1231
#, fuzzy
#| msgid "Instructions"
msgid "Instruction Replace"
msgstr "Istruzioni"
msgstr "Sostituisci Istruzione"
#: .\cookbook\models.py:1257 .\cookbook\views\delete.py:36
#: .\cookbook\views\edit.py:251 .\cookbook\views\new.py:48
@@ -787,6 +787,8 @@ msgstr ""
msgid ""
"Providing a list_recipe ID and servings of 0 will delete that shopping list."
msgstr ""
"Fornendo un ID list_recipe e impostando le porzioni a 0, la lista della "
"spesa verrà eliminata."
#: .\cookbook\serializer.py:1247
msgid "Amount of food to add to the shopping list"
@@ -1485,10 +1487,8 @@ msgstr ""
#: .\cookbook\templates\markdown_info.html:57
#: .\cookbook\templates\markdown_info.html:73
#, fuzzy
#| msgid "or by leaving a blank line inbetween."
msgid "or by leaving a blank line in between."
msgstr "o lasciando una riga vuota in mezzo."
msgstr "oppure lasciando una riga vuota tra di loro."
#: .\cookbook\templates\markdown_info.html:59
#: .\cookbook\templates\markdown_info.html:74
@@ -1510,10 +1510,6 @@ msgid "Lists"
msgstr "Liste"
#: .\cookbook\templates\markdown_info.html:85
#, fuzzy
#| msgid ""
#| "Lists can ordered or unorderd. It is <b>important to leave a blank line "
#| "before the list!</b>"
msgid ""
"Lists can ordered or unordered. It is <b>important to leave a blank line "
"before the list!</b>"
@@ -1650,7 +1646,7 @@ msgstr "Indietro"
#: .\cookbook\templates\profile.html:7
msgid "Profile"
msgstr ""
msgstr "Profilo"
#: .\cookbook\templates\recipe_view.html:26
msgid "by"
@@ -1709,6 +1705,18 @@ msgid ""
"html#TEXTSEARCH-PARSING-QUERIES>Postgresql's website.</a>\n"
" "
msgstr ""
" \n"
" Le ricerche full-text cercano di normalizzare le parole fornite "
"per abbinare varianti comuni. Ad esempio, \"separato\", \"separando\", "
"\"separa\" verranno tutti normalizzati in \"separare\".\n"
" Ci sono diversi metodi disponibili, descritti di seguito, che "
"controlleranno il comportamento della ricerca in caso di ricerca con più "
"parole.\n"
" I dettagli tecnici completi su come questi funzionano possono "
"essere visualizzati sul <a href=https://www.postgresql.org/docs/current/"
"textsearch-controls.html#TEXTSEARCH-PARSING-QUERIES>sito web di "
"Postgresql.</a>\n"
" "
#: .\cookbook\templates\search_info.html:29
msgid ""

View File

@@ -13,16 +13,16 @@ msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2023-01-19 19:14+0100\n"
"PO-Revision-Date: 2022-09-01 20:32+0000\n"
"Last-Translator: 1k2 <tandoor@1k2.nl>\n"
"Language-Team: Dutch <http://translate.tandoor.dev/projects/tandoor/recipes-"
"backend/nl/>\n"
"PO-Revision-Date: 2023-02-27 13:55+0000\n"
"Last-Translator: Jesse <jesse.kamps@pm.me>\n"
"Language-Team: Dutch <http://translate.tandoor.dev/projects/tandoor/"
"recipes-backend/nl/>\n"
"Language: nl\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
"X-Generator: Weblate 4.10.1\n"
"X-Generator: Weblate 4.15\n"
#: .\cookbook\forms.py:52
msgid "Default unit"
@@ -473,7 +473,7 @@ msgstr "Toon recepten teller bij zoekfilters"
#: .\cookbook\forms.py:541
msgid "Use the plural form for units and food inside this space."
msgstr ""
msgstr "Gebruik de meervoudsvorm voor eenheden en voedsel in deze ruimte."
#: .\cookbook\helper\AllAuthCustomAdapter.py:39
msgid ""
@@ -537,7 +537,7 @@ msgstr "Favoriet"
#: .\cookbook\integration\copymethat.py:50
msgid "I made this"
msgstr ""
msgstr "Ik heb dit gemaakt"
#: .\cookbook\integration\integration.py:223
msgid ""
@@ -691,16 +691,12 @@ msgid "Keyword Alias"
msgstr "Etiket alias"
#: .\cookbook\models.py:1231
#, fuzzy
#| msgid "Description"
msgid "Description Replace"
msgstr "Beschrijving"
msgstr "Verrvang beschrijving"
#: .\cookbook\models.py:1231
#, fuzzy
#| msgid "Instructions"
msgid "Instruction Replace"
msgstr "Instructies"
msgstr "Vervang instructies"
#: .\cookbook\models.py:1257 .\cookbook\views\delete.py:36
#: .\cookbook\views\edit.py:251 .\cookbook\views\new.py:48
@@ -725,7 +721,7 @@ msgstr "U heeft de uploadlimiet bereikt."
#: .\cookbook\serializer.py:291
msgid "Cannot modify Space owner permission."
msgstr ""
msgstr "Kan de rechten van de ruimte-eigenaar niet wijzigen."
#: .\cookbook\serializer.py:1085
msgid "Hello"
@@ -1634,7 +1630,7 @@ msgstr "Terug"
#: .\cookbook\templates\profile.html:7
msgid "Profile"
msgstr ""
msgstr "Profiel"
#: .\cookbook\templates\recipe_view.html:26
msgid "by"
@@ -2039,6 +2035,8 @@ msgstr "Verbind %(provider)s"
#, python-format
msgid "You are about to connect a new third party account from %(provider)s."
msgstr ""
"Je staat op het punt een nieuw derde partij account van %(provider)s te "
"verbinden."
#: .\cookbook\templates\socialaccount\login.html:13
#, python-format
@@ -2049,6 +2047,8 @@ msgstr "Log in via %(provider)s"
#, python-format
msgid "You are about to sign in using a third party account from %(provider)s."
msgstr ""
"Je staat op het punt met een derde partij account van %(provider)s in te "
"loggen."
#: .\cookbook\templates\socialaccount\login.html:20
msgid "Continue"
@@ -2092,7 +2092,7 @@ msgstr "Beheer abonnementen"
#: .\cookbook\templates\space_overview.html:13 .\cookbook\views\delete.py:216
msgid "Space"
msgstr "Space"
msgstr "Ruimte"
#: .\cookbook\templates\space_overview.html:17
msgid ""

View File

@@ -8,8 +8,8 @@ msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2022-02-11 08:52+0100\n"
"PO-Revision-Date: 2022-03-08 01:31+0000\n"
"Last-Translator: Felipe Castro <felipefcastro@gmail.com>\n"
"PO-Revision-Date: 2023-02-18 10:55+0000\n"
"Last-Translator: Joachim Weber <joachim.weber@gmx.de>\n"
"Language-Team: Portuguese (Brazil) <http://translate.tandoor.dev/projects/"
"tandoor/recipes-backend/pt_BR/>\n"
"Language: pt_BR\n"
@@ -17,7 +17,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n > 1;\n"
"X-Generator: Weblate 4.10.1\n"
"X-Generator: Weblate 4.15\n"
#: .\cookbook\filters.py:23 .\cookbook\templates\forms\ingredients.html:34
#: .\cookbook\templates\space.html:50 .\cookbook\templates\stats.html:28
@@ -158,7 +158,7 @@ msgstr ""
#: .\cookbook\templates\url_import.html:195
#: .\cookbook\templates\url_import.html:585 .\cookbook\views\lists.py:97
msgid "Keywords"
msgstr ""
msgstr "Palavras-chave"
#: .\cookbook\forms.py:131
msgid "Preparation time in minutes"
@@ -513,7 +513,7 @@ msgstr ""
#: .\cookbook\templates\url_import.html:231
#: .\cookbook\templates\url_import.html:462
msgid "Servings"
msgstr ""
msgstr "Porções"
#: .\cookbook\integration\saffron.py:25
msgid "Waiting time"
@@ -585,7 +585,7 @@ msgstr ""
#: .\cookbook\models.py:302 .\cookbook\templates\base.html:90
msgid "Books"
msgstr ""
msgstr "Livros"
#: .\cookbook\models.py:310
msgid "Small"
@@ -598,7 +598,7 @@ msgstr ""
#: .\cookbook\models.py:310 .\cookbook\templates\generic\new_template.html:6
#: .\cookbook\templates\generic\new_template.html:14
msgid "New"
msgstr ""
msgstr "Novo"
#: .\cookbook\models.py:513
msgid " is part of a recipe step and cannot be deleted"
@@ -677,7 +677,7 @@ msgstr ""
#: .\cookbook\templates\shopping_list.html:37
#: .\cookbook\templates\space.html:109
msgid "Edit"
msgstr ""
msgstr "Editar"
#: .\cookbook\tables.py:115 .\cookbook\tables.py:138
#: .\cookbook\templates\generic\delete_template.html:7
@@ -715,7 +715,7 @@ msgstr ""
#: .\cookbook\templates\settings.html:17
#: .\cookbook\templates\socialaccount\connections.html:10
msgid "Settings"
msgstr ""
msgstr "Configurações"
#: .\cookbook\templates\account\email.html:13
msgid "Email"
@@ -937,7 +937,7 @@ msgstr ""
#: .\cookbook\templates\account\signup.html:48
#: .\cookbook\templates\socialaccount\signup.html:39
msgid "and"
msgstr ""
msgstr "e"
#: .\cookbook\templates\account\signup.html:52
#: .\cookbook\templates\socialaccount\signup.html:43
@@ -989,7 +989,7 @@ msgstr ""
#: .\cookbook\templates\shopping_list.html:208
#: .\cookbook\templates\supermarket.html:7
msgid "Supermarket"
msgstr ""
msgstr "Supermercado"
#: .\cookbook\templates\base.html:163
msgid "Supermarket Category"
@@ -1027,7 +1027,7 @@ msgstr ""
#: .\cookbook\templates\shopping_list.html:165
#: .\cookbook\templates\shopping_list.html:188
msgid "Create"
msgstr ""
msgstr "Criar"
#: .\cookbook\templates\base.html:259
#: .\cookbook\templates\generic\list_template.html:14
@@ -1190,7 +1190,7 @@ msgstr ""
#: .\cookbook\templates\generic\delete_template.html:26
msgid "Protected"
msgstr ""
msgstr "Protegido"
#: .\cookbook\templates\generic\delete_template.html:41
msgid "Cascade"
@@ -1268,7 +1268,7 @@ msgstr ""
#: .\cookbook\templates\include\recipe_open_modal.html:18
msgid "Close"
msgstr ""
msgstr "Fechar"
#: .\cookbook\templates\include\recipe_open_modal.html:32
msgid "Open Recipe"
@@ -1821,7 +1821,7 @@ msgstr ""
#: .\cookbook\templates\settings.html:162
msgid "or"
msgstr ""
msgstr "ou"
#: .\cookbook\templates\settings.html:173
msgid ""
@@ -2062,7 +2062,7 @@ msgstr ""
#: .\cookbook\templates\space.html:120
msgid "user"
msgstr ""
msgstr "usuário"
#: .\cookbook\templates\space.html:121
msgid "guest"
@@ -2273,7 +2273,7 @@ msgstr ""
#: .\cookbook\templates\url_import.html:214
msgid "Image"
msgstr ""
msgstr "Imagem"
#: .\cookbook\templates\url_import.html:246
msgid "Prep Time"
@@ -2359,7 +2359,7 @@ msgstr ""
#: .\cookbook\templates\url_import.html:640
msgid "Information"
msgstr ""
msgstr "Informação"
#: .\cookbook\templates\url_import.html:642
msgid ""

View File

@@ -8,15 +8,17 @@ msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2022-04-29 18:42+0200\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: Automatically generated\n"
"Language-Team: none\n"
"PO-Revision-Date: 2023-02-09 13:55+0000\n"
"Last-Translator: vertilo <vertilo.dev@gmail.com>\n"
"Language-Team: Ukrainian <http://translate.tandoor.dev/projects/tandoor/"
"recipes-backend/uk/>\n"
"Language: uk\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n"
"%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n"
"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && "
"n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n"
"X-Generator: Weblate 4.15\n"
#: .\cookbook\filters.py:23 .\cookbook\templates\forms\ingredients.html:34
#: .\cookbook\templates\space.html:49 .\cookbook\templates\stats.html:28
@@ -2026,7 +2028,7 @@ msgstr ""
#: .\cookbook\templates\space.html:118
msgid "user"
msgstr ""
msgstr "користувач"
#: .\cookbook\templates\space.html:119
msgid "guest"

View File

@@ -8,7 +8,7 @@ msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2023-01-19 19:14+0100\n"
"PO-Revision-Date: 2022-08-23 13:32+0000\n"
"PO-Revision-Date: 2023-02-26 13:15+0000\n"
"Last-Translator: 吕楪 <thy@irithys.com>\n"
"Language-Team: Chinese (Simplified) <http://translate.tandoor.dev/projects/"
"tandoor/recipes-backend/zh_Hans/>\n"
@@ -17,7 +17,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=1; plural=0;\n"
"X-Generator: Weblate 4.10.1\n"
"X-Generator: Weblate 4.15\n"
#: .\cookbook\forms.py:52
msgid "Default unit"
@@ -434,7 +434,7 @@ msgstr "显示搜索筛选器上的食谱计数"
#: .\cookbook\forms.py:541
msgid "Use the plural form for units and food inside this space."
msgstr ""
msgstr "在此空间内使用复数形式表示单位和食物。"
#: .\cookbook\helper\AllAuthCustomAdapter.py:39
msgid ""
@@ -495,7 +495,7 @@ msgstr "喜欢"
#: .\cookbook\integration\copymethat.py:50
msgid "I made this"
msgstr ""
msgstr "我做的"
#: .\cookbook\integration\integration.py:223
msgid ""
@@ -642,16 +642,12 @@ msgid "Keyword Alias"
msgstr "关键词别名"
#: .\cookbook\models.py:1231
#, fuzzy
#| msgid "Description"
msgid "Description Replace"
msgstr "描述"
#: .\cookbook\models.py:1231
#, fuzzy
#| msgid "Instructions"
msgid "Instruction Replace"
msgstr "说明"
msgstr "指示"
#: .\cookbook\models.py:1257 .\cookbook\views\delete.py:36
#: .\cookbook\views\edit.py:251 .\cookbook\views\new.py:48
@@ -1555,7 +1551,7 @@ msgstr "返回"
#: .\cookbook\templates\profile.html:7
msgid "Profile"
msgstr ""
msgstr "简介"
#: .\cookbook\templates\recipe_view.html:26
msgid "by"
@@ -2173,10 +2169,9 @@ msgid "Cannot merge with the same object!"
msgstr "无法与同一对象合并!"
#: .\cookbook\views\api.py:232
#, fuzzy, python-brace-format
#| msgid "No {self.basename} with id {target} exists"
#, python-brace-format
msgid "No {self.basename} with id {target} exists"
msgstr "不存在 ID 为 {pk} 的 {self.basename}"
msgstr "不存在 ID 为 {target} 的 {self.basename}"
#: .\cookbook\views\api.py:237
msgid "Cannot merge with child object!"

View File

@@ -8,14 +8,16 @@ msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2021-06-12 20:30+0200\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: Automatically generated\n"
"Language-Team: none\n"
"PO-Revision-Date: 2023-03-12 02:55+0000\n"
"Last-Translator: Feng Zhong <fewoodse@gmail.com>\n"
"Language-Team: Chinese (Traditional) <http://translate.tandoor.dev/projects/"
"tandoor/recipes-backend/zh_Hant/>\n"
"Language: zh_Hant\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=1; plural=0;\n"
"X-Generator: Weblate 4.15\n"
#: .\cookbook\filters.py:23 .\cookbook\templates\base.html:98
#: .\cookbook\templates\forms\edit_internal_recipe.html:246
@@ -23,41 +25,41 @@ msgstr ""
#: .\cookbook\templates\space.html:37 .\cookbook\templates\stats.html:28
#: .\cookbook\templates\url_import.html:270 .\cookbook\views\lists.py:67
msgid "Ingredients"
msgstr ""
msgstr "食材"
#: .\cookbook\forms.py:49
msgid ""
"Color of the top navigation bar. Not all colors work with all themes, just "
"try them out!"
msgstr ""
msgstr "頂部導航欄的顏色。並非所有的顏色都適用於所有的主題,只要試一試就可以了!"
#: .\cookbook\forms.py:51
msgid "Default Unit to be used when inserting a new ingredient into a recipe."
msgstr ""
msgstr "在菜譜中插入新食材時使用的默認單位。"
#: .\cookbook\forms.py:53
msgid ""
"Enables support for fractions in ingredient amounts (e.g. convert decimals "
"to fractions automatically)"
msgstr ""
msgstr "啟用對食材數量的分數支持(例如自動將小數轉換為分數)"
#: .\cookbook\forms.py:56
msgid ""
"Users with whom newly created meal plan/shopping list entries should be "
"shared by default."
msgstr ""
msgstr "默認情況下,將自動與用戶共享新創建的膳食計劃。"
#: .\cookbook\forms.py:58
msgid "Show recently viewed recipes on search page."
msgstr ""
msgstr "在搜索頁面上查看最近看過的食譜。"
#: .\cookbook\forms.py:59
msgid "Number of decimals to round ingredients."
msgstr ""
msgstr "四舍五入食材的小數點數量。"
#: .\cookbook\forms.py:60
msgid "If you want to be able to create and see comments underneath recipes."
msgstr ""
msgstr "如果你希望能夠在菜譜下面創建並看到評論。"
#: .\cookbook\forms.py:62
msgid ""
@@ -66,22 +68,25 @@ msgid ""
"Useful when shopping with multiple people but might use a little bit of "
"mobile data. If lower than instance limit it is reset when saving."
msgstr ""
"設置為0將禁用自動同步。當查看購物清單時清單會每隔幾秒鐘更新一次以同步其他"
"人可能做出的改變。在與多人一起購物時很有用,但可能會消耗一點移動數據。如果低"
"於實例限制,它將在保存時被重置。"
#: .\cookbook\forms.py:65
msgid "Makes the navbar stick to the top of the page."
msgstr ""
msgstr "使導航欄保持在頁面的頂部。"
#: .\cookbook\forms.py:81
msgid ""
"Both fields are optional. If none are given the username will be displayed "
"instead"
msgstr ""
msgstr "這兩個字段都是可選的。如果沒有輸入,將顯示用戶名"
#: .\cookbook\forms.py:102 .\cookbook\forms.py:331
#: .\cookbook\templates\forms\edit_internal_recipe.html:49
#: .\cookbook\templates\url_import.html:154
msgid "Name"
msgstr ""
msgstr "名字"
#: .\cookbook\forms.py:103 .\cookbook\forms.py:332
#: .\cookbook\templates\base.html:105
@@ -90,37 +95,37 @@ msgstr ""
#: .\cookbook\templates\url_import.html:188
#: .\cookbook\templates\url_import.html:573
msgid "Keywords"
msgstr ""
msgstr "關鍵詞"
#: .\cookbook\forms.py:104
msgid "Preparation time in minutes"
msgstr ""
msgstr "準備時間(分鐘)"
#: .\cookbook\forms.py:105
msgid "Waiting time (cooking/baking) in minutes"
msgstr ""
msgstr "等候(烹飪、烘焙等)時間(分鐘)"
#: .\cookbook\forms.py:106 .\cookbook\forms.py:333
msgid "Path"
msgstr ""
msgstr "路徑"
#: .\cookbook\forms.py:107
msgid "Storage UID"
msgstr ""
msgstr "存儲ID"
#: .\cookbook\forms.py:133
msgid "Default"
msgstr ""
msgstr "默認"
#: .\cookbook\forms.py:144 .\cookbook\templates\url_import.html:90
msgid ""
"To prevent duplicates recipes with the same name as existing ones are "
"ignored. Check this box to import everything."
msgstr ""
msgstr "為防止重復,忽略與現有同名的菜譜。選中此框可導入所有內容(包括同名菜譜)。"
#: .\cookbook\forms.py:164
msgid "New Unit"
msgstr ""
msgstr "新單位"
#: .\cookbook\forms.py:165
msgid "New unit that other gets replaced by."
@@ -128,15 +133,15 @@ msgstr ""
#: .\cookbook\forms.py:170
msgid "Old Unit"
msgstr ""
msgstr "舊單位"
#: .\cookbook\forms.py:171
msgid "Unit that should be replaced."
msgstr ""
msgstr "該被替換的單位。"
#: .\cookbook\forms.py:187
msgid "New Food"
msgstr ""
msgstr "新食物"
#: .\cookbook\forms.py:188
msgid "New food that other gets replaced by."
@@ -144,85 +149,86 @@ msgstr ""
#: .\cookbook\forms.py:193
msgid "Old Food"
msgstr ""
msgstr "舊食物"
#: .\cookbook\forms.py:194
msgid "Food that should be replaced."
msgstr ""
msgstr "該被替換的食物。"
#: .\cookbook\forms.py:212
msgid "Add your comment: "
msgstr ""
msgstr "發表評論。 "
#: .\cookbook\forms.py:253
msgid "Leave empty for dropbox and enter app password for nextcloud."
msgstr ""
msgstr "Dropbox 留空並輸入 Nextcloud 應用密碼。"
#: .\cookbook\forms.py:260
msgid "Leave empty for nextcloud and enter api token for dropbox."
msgstr ""
msgstr "Nextcloud 留空並輸入 Dropbox API 令牌。"
#: .\cookbook\forms.py:269
msgid ""
"Leave empty for dropbox and enter only base url for nextcloud (<code>/remote."
"php/webdav/</code> is added automatically)"
msgstr ""
msgstr "Dropbox 留空並輸入基礎 Nextcloud 網址(<code>/remote.php/webdav/</code> "
"會自動添加)"
#: .\cookbook\forms.py:307
msgid "Search String"
msgstr ""
msgstr "搜索字符串"
#: .\cookbook\forms.py:334
msgid "File ID"
msgstr ""
msgstr "文件編號"
#: .\cookbook\forms.py:370
msgid "You must provide at least a recipe or a title."
msgstr ""
msgstr "你必須至少提供一份菜譜或一個標題。"
#: .\cookbook\forms.py:383
msgid "You can list default users to share recipes with in the settings."
msgstr ""
msgstr "你可以在設置中列出默認用戶來分享菜譜。"
#: .\cookbook\forms.py:384
#: .\cookbook\templates\forms\edit_internal_recipe.html:404
msgid ""
"You can use markdown to format this field. See the <a href=\"/docs/markdown/"
"\">docs here</a>"
msgstr ""
msgstr "可以使用 Markdown 設置此字段格式。<a href=\"/docs/markdown/\">查看文檔</a>"
#: .\cookbook\forms.py:409
msgid "Maximum number of users for this space reached."
msgstr ""
msgstr "已達到該空間的最大用戶數。"
#: .\cookbook\forms.py:415
msgid "Email address already taken!"
msgstr ""
msgstr "電子郵件地址已被註冊!"
#: .\cookbook\forms.py:423
msgid ""
"An email address is not required but if present the invite link will be send "
"to the user."
msgstr ""
msgstr "電子郵件地址不是必需的,但如果存在,邀請鏈接將被發送給用戶。"
#: .\cookbook\forms.py:438
msgid "Name already taken."
msgstr ""
msgstr "名字已被占用。"
#: .\cookbook\forms.py:449
msgid "Accept Terms and Privacy"
msgstr ""
msgstr "接受條款及隱私政策"
#: .\cookbook\helper\AllAuthCustomAdapter.py:30
msgid ""
"In order to prevent spam, the requested email was not send. Please wait a "
"few minutes and try again."
msgstr ""
msgstr "為了防止垃圾郵件,所要求的電子郵件沒有被發送。請等待幾分鐘後再試。"
#: .\cookbook\helper\permission_helper.py:124
#: .\cookbook\helper\permission_helper.py:144 .\cookbook\views\views.py:147
msgid "You are not logged in and therefore cannot view this page!"
msgstr ""
msgstr "你还沒有登錄,因此不能查看這個頁面!"
#: .\cookbook\helper\permission_helper.py:127
#: .\cookbook\helper\permission_helper.py:132
@@ -234,18 +240,18 @@ msgstr ""
#: .\cookbook\views\views.py:158 .\cookbook\views\views.py:165
#: .\cookbook\views\views.py:253
msgid "You do not have the required permissions to view this page!"
msgstr ""
msgstr "你沒有必要的權限來查看這個頁面!"
#: .\cookbook\helper\permission_helper.py:148
#: .\cookbook\helper\permission_helper.py:170
#: .\cookbook\helper\permission_helper.py:185
msgid "You cannot interact with this object as it is not owned by you!"
msgstr ""
msgstr "你不能與此對象交互,因為它不屬於你!"
#: .\cookbook\helper\template_helper.py:60
#: .\cookbook\helper\template_helper.py:62
msgid "Could not parse template code."
msgstr ""
msgstr "無法解析模板代碼。"
#: .\cookbook\integration\integration.py:102
#: .\cookbook\templates\import.html:14 .\cookbook\templates\import.html:20
@@ -258,40 +264,40 @@ msgstr ""
#: .\cookbook\templates\url_import.html:604 .\cookbook\views\delete.py:60
#: .\cookbook\views\edit.py:199
msgid "Import"
msgstr ""
msgstr "導入"
#: .\cookbook\integration\integration.py:162
msgid ""
"Importer expected a .zip file. Did you choose the correct importer type for "
"your data ?"
msgstr ""
msgstr "導入需要一個 .zip 文件。你是否為數據選擇了正確的導入器類型?"
#: .\cookbook\integration\integration.py:165
msgid ""
"An unexpected error occurred during the import. Please make sure you have "
"uploaded a valid file."
msgstr ""
msgstr "在導入過程中發生了一個意外的錯誤。請確認你上傳的文件是否有效。"
#: .\cookbook\integration\integration.py:169
msgid "The following recipes were ignored because they already existed:"
msgstr ""
msgstr "以下菜譜被忽略了,因為它們已經存在了:"
#: .\cookbook\integration\integration.py:173
#, python-format
msgid "Imported %s recipes."
msgstr ""
msgstr "導入了%s菜譜。"
#: .\cookbook\integration\paprika.py:46
msgid "Notes"
msgstr ""
msgstr "說明"
#: .\cookbook\integration\paprika.py:49
msgid "Nutritional Information"
msgstr ""
msgstr "營養信息"
#: .\cookbook\integration\paprika.py:53
msgid "Source"
msgstr ""
msgstr "來源"
#: .\cookbook\integration\safron.py:23
#: .\cookbook\templates\forms\edit_internal_recipe.html:79
@@ -299,101 +305,101 @@ msgstr ""
#: .\cookbook\templates\url_import.html:224
#: .\cookbook\templates\url_import.html:455
msgid "Servings"
msgstr ""
msgstr "份量"
#: .\cookbook\integration\safron.py:25
msgid "Waiting time"
msgstr ""
msgstr "等待時間"
#: .\cookbook\integration\safron.py:27
#: .\cookbook\templates\forms\edit_internal_recipe.html:73
msgid "Preparation Time"
msgstr ""
msgstr "準備時間"
#: .\cookbook\integration\safron.py:29 .\cookbook\templates\base.html:78
#: .\cookbook\templates\forms\ingredients.html:7
#: .\cookbook\templates\index.html:7
msgid "Cookbook"
msgstr ""
msgstr "菜譜"
#: .\cookbook\integration\safron.py:31
msgid "Section"
msgstr ""
msgstr "部分"
#: .\cookbook\migrations\0047_auto_20200602_1133.py:14
msgid "Breakfast"
msgstr ""
msgstr "早餐"
#: .\cookbook\migrations\0047_auto_20200602_1133.py:19
msgid "Lunch"
msgstr ""
msgstr "午餐"
#: .\cookbook\migrations\0047_auto_20200602_1133.py:24
msgid "Dinner"
msgstr ""
msgstr "晚餐"
#: .\cookbook\migrations\0047_auto_20200602_1133.py:29
msgid "Other"
msgstr ""
msgstr "其他"
#: .\cookbook\models.py:71
msgid ""
"Maximum file storage for space in MB. 0 for unlimited, -1 to disable file "
"upload."
msgstr ""
msgstr "空間的最大文件存儲量,單位為 MB。0表示無限製-1表示禁止上傳文件。"
#: .\cookbook\models.py:121 .\cookbook\templates\search.html:7
#: .\cookbook\templates\shopping_list.html:52
msgid "Search"
msgstr ""
msgstr "搜索"
#: .\cookbook\models.py:122 .\cookbook\templates\base.html:92
#: .\cookbook\templates\meal_plan.html:5 .\cookbook\views\delete.py:152
#: .\cookbook\views\edit.py:233 .\cookbook\views\new.py:201
msgid "Meal-Plan"
msgstr ""
msgstr "膳食計劃"
#: .\cookbook\models.py:123 .\cookbook\templates\base.html:89
msgid "Books"
msgstr ""
msgstr "書籍"
#: .\cookbook\models.py:131
msgid "Small"
msgstr ""
msgstr ""
#: .\cookbook\models.py:131
msgid "Large"
msgstr ""
msgstr ""
#: .\cookbook\models.py:131 .\cookbook\templates\generic\new_template.html:6
#: .\cookbook\templates\generic\new_template.html:14
#: .\cookbook\templates\meal_plan.html:323
msgid "New"
msgstr ""
msgstr ""
#: .\cookbook\models.py:340
#: .\cookbook\templates\forms\edit_internal_recipe.html:202
msgid "Text"
msgstr ""
msgstr "文本"
#: .\cookbook\models.py:340
#: .\cookbook\templates\forms\edit_internal_recipe.html:203
msgid "Time"
msgstr ""
msgstr "時間"
#: .\cookbook\models.py:340
#: .\cookbook\templates\forms\edit_internal_recipe.html:204
#: .\cookbook\templates\forms\edit_internal_recipe.html:218
msgid "File"
msgstr ""
msgstr "文件"
#: .\cookbook\serializer.py:109
msgid "File uploads are not enabled for this Space."
msgstr ""
msgstr "未為此空間啟用文件上傳。"
#: .\cookbook\serializer.py:117
msgid "You have reached your file upload limit."
msgstr ""
msgstr "你已達到文件上傳的限製。"
#: .\cookbook\tables.py:35 .\cookbook\templates\books.html:36
#: .\cookbook\templates\generic\edit_template.html:6
@@ -403,7 +409,7 @@ msgstr ""
#: .\cookbook\templates\shopping_list.html:33
#: .\cookbook\templates\space.html:84
msgid "Edit"
msgstr ""
msgstr "編輯"
#: .\cookbook\tables.py:124 .\cookbook\tables.py:147
#: .\cookbook\templates\books.html:38
@@ -413,28 +419,28 @@ msgstr ""
#: .\cookbook\templates\meal_plan.html:277
#: .\cookbook\templates\recipes_table.html:90
msgid "Delete"
msgstr ""
msgstr "刪除"
#: .\cookbook\templates\404.html:5
msgid "404 Error"
msgstr ""
msgstr "404錯誤"
#: .\cookbook\templates\404.html:18
msgid "The page you are looking for could not be found."
msgstr ""
msgstr "找不到你要找的頁面。"
#: .\cookbook\templates\404.html:33
msgid "Take me Home"
msgstr ""
msgstr "回到主頁"
#: .\cookbook\templates\404.html:35
msgid "Report a Bug"
msgstr ""
msgstr "報告一個錯誤"
#: .\cookbook\templates\account\email.html:6
#: .\cookbook\templates\account\email.html:9
msgid "E-mail Addresses"
msgstr ""
msgstr "電子郵件地址"
#: .\cookbook\templates\account\email.html:11
msgid "The following e-mail addresses are associated with your account:"
@@ -1769,7 +1775,7 @@ msgstr ""
#: .\cookbook\templates\space.html:100
msgid "user"
msgstr ""
msgstr "用戶"
#: .\cookbook\templates\space.html:101
msgid "guest"

View File

@@ -0,0 +1,18 @@
# Generated by Django 4.1.4 on 2023-02-12 16:44
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('cookbook', '0187_alter_space_use_plural'),
]
operations = [
migrations.AddField(
model_name='space',
name='no_sharing_limit',
field=models.BooleanField(default=False),
),
]

View File

@@ -262,6 +262,7 @@ class Space(ExportModelOperationsMixin('space'), models.Model):
max_users = models.IntegerField(default=0)
use_plural = models.BooleanField(default=True)
allow_sharing = models.BooleanField(default=True)
no_sharing_limit = models.BooleanField(default=False)
demo = models.BooleanField(default=False)
food_inherit = models.ManyToManyField(FoodInheritField, blank=True)
show_facet_count = models.BooleanField(default=False)
@@ -680,7 +681,7 @@ class Ingredient(ExportModelOperationsMixin('ingredient'), models.Model, Permiss
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.plural_name not in (None, "") and not self.no_amount:
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)

View File

@@ -432,9 +432,13 @@ class UnitSerializer(UniqueFieldsMixin, ExtendedRecipeMixin):
def create(self, validated_data):
name = validated_data.pop('name').strip()
plural_name = validated_data.pop('plural_name', None)
if plural_name:
if plural_name := validated_data.pop('plural_name', None):
plural_name = plural_name.strip()
if unit := Unit.objects.filter(Q(name=name) | Q(plural_name=name)).first():
return unit
space = validated_data.pop('space', self.context['request'].space)
obj, created = Unit.objects.get_or_create(name=name, plural_name=plural_name, space=space, defaults=validated_data)
return obj
@@ -544,9 +548,13 @@ class FoodSerializer(UniqueFieldsMixin, WritableNestedModelSerializer, ExtendedR
def create(self, validated_data):
name = validated_data.pop('name').strip()
plural_name = validated_data.pop('plural_name', None)
if plural_name:
if plural_name := validated_data.pop('plural_name', None):
plural_name = plural_name.strip()
if food := Food.objects.filter(Q(name=name) | Q(plural_name=name)).first():
return food
space = validated_data.pop('space', self.context['request'].space)
# supermarket category needs to be handled manually as food.get or create does not create nested serializers unlike a super.create of serializer
if 'supermarket_category' in validated_data and validated_data['supermarket_category']:

View File

@@ -2,6 +2,16 @@
height: 40px;
}
.two-row-text {
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 2; /* number of lines to show */
line-clamp: 2;
-webkit-box-orient: vertical;
}
@media (max-width: 991.98px) {
.menu-dropdown-text {
font-size: 14px;

View File

@@ -350,8 +350,8 @@
{% message_of_the_day request as message_of_the_day %}
{% if message_of_the_day %}
<div class="bg-success" style=" width: 100%; text-align: center!important; color: #ffffff; padding: 8px">
{{ message_of_the_day }}
<div class="bg-info" style=" width: 100%; text-align: center!important; color: #ffffff; padding: 8px">
{{ message_of_the_day | markdown |safe }}
</div>
{% endif %}

View File

@@ -7,6 +7,21 @@
{% block title %}{{ recipe.name }}{% endblock %}
{% block extra_head %}
<meta property="og:title" content="{{ recipe.name }}"/>
<meta property="og:type" content="website"/>
<meta property="og:url" content="{% base_path request 'base' %}{% url 'view_recipe' recipe.pk share %}"/>
{% if recipe.image %}
<meta property="og:image" content="{% base_path request 'base' %}{{ recipe.image.url }}"/>
<meta property="og:image:url" content="{% base_path request 'base' %}{{ recipe.image.url }}"/>
<meta property="og:image:secure" content="{% base_path request 'base' %}{{ recipe.image.url }}"/>
{% endif %}
{% if recipe.description %}
<meta property="og:description" content="{{ recipe.description }}"/>
{% endif %}
<meta property="og:site_name" content="Tandoor Recipes"/>
{% endblock %}
{% block content %}
{% recipe_rating recipe request.user as rating %}
@@ -33,7 +48,7 @@
{% endfor %}
{% if request.user.is_authenticated %}
<div class="d-print-none">
<div class="d-print-none" style="padding-bottom: 60px">
<form method="POST" class="post-form">
{% csrf_token %}

View File

@@ -10,7 +10,9 @@
{% block content_fluid %}
{{ data }}
<div id="app">
<test-view></test-view>
</div>
{% endblock %}

View File

@@ -57,6 +57,8 @@ def markdown(value):
]
)
markdown_attrs['*'] = markdown_attrs['*'] + ['class']
parsed_md = parsed_md[3:] # remove outer paragraph
parsed_md = parsed_md[:len(parsed_md)-4]
return bleach.clean(parsed_md, tags, markdown_attrs)

View File

@@ -1,6 +1,7 @@
import io
import json
import mimetypes
import pathlib
import re
import threading
import traceback
@@ -56,7 +57,7 @@ from cookbook.helper.permission_helper import (CustomIsAdmin, CustomIsOwner,
CustomIsSpaceOwner, CustomIsUser, group_required,
is_space_owner, switch_user_active_space, above_space_limit, CustomRecipePermission, CustomUserPermission, CustomTokenHasReadWriteScope, CustomTokenHasScope, has_group_permission)
from cookbook.helper.recipe_search import RecipeFacet, RecipeSearch
from cookbook.helper.recipe_url_import import get_from_youtube_scraper, get_images_from_soup
from cookbook.helper.recipe_url_import import get_from_youtube_scraper, get_images_from_soup, clean_dict
from cookbook.helper.scrapers.scrapers import text_scraper
from cookbook.helper.shopping_helper import RecipeShoppingEditor, shopping_helper
from cookbook.models import (Automation, BookmarkletImport, CookLog, CustomFilter, ExportLog, Food,
@@ -87,7 +88,7 @@ from cookbook.serializer import (AutomationSerializer, BookmarkletImportListSeri
SupermarketCategorySerializer, SupermarketSerializer,
SyncLogSerializer, SyncSerializer, UnitSerializer,
UserFileSerializer, UserSerializer, UserPreferenceSerializer,
UserSpaceSerializer, ViewLogSerializer, AccessTokenSerializer)
UserSpaceSerializer, ViewLogSerializer, AccessTokenSerializer, FoodSimpleSerializer, RecipeExportSerializer)
from cookbook.views.import_export import get_integration
from recipes import settings
@@ -533,6 +534,11 @@ class FoodViewSet(viewsets.ModelViewSet, TreeMixin):
.prefetch_related('onhand_users', 'inherit_fields', 'child_inherit_fields', 'substitute') \
.select_related('recipe', 'supermarket_category')
def get_serializer_class(self):
if self.request and self.request.query_params.get('simple', False):
return FoodSimpleSerializer
return self.serializer_class
@decorators.action(detail=True, methods=['PUT'], serializer_class=FoodShoppingUpdateSerializer, )
# TODO DRF only allows one action in a decorator action without overriding get_operation_id_base() this should be PUT and DELETE probably
def shopping(self, request, pk):
@@ -655,7 +661,7 @@ class IngredientViewSet(viewsets.ModelViewSet):
def get_serializer_class(self):
if self.request and self.request.query_params.get('simple', False):
return IngredientSimpleSerializer
return IngredientSerializer
return self.serializer_class
def get_queryset(self):
queryset = self.queryset.filter(step__recipe__space=self.request.space)
@@ -1169,6 +1175,18 @@ def recipe_from_source(request):
# 'recipe_html': '',
'recipe_images': [],
}, status=status.HTTP_200_OK)
if re.match('^(.)*/view/recipe/[0-9]+/[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$', url):
recipe_json = requests.get(url.replace('/view/recipe/', '/api/recipe/').replace(re.split('/view/recipe/[0-9]+', url)[1], '') + '?share=' + re.split('/view/recipe/[0-9]+', url)[1].replace('/', '')).json()
recipe_json = clean_dict(recipe_json, 'id')
serialized_recipe = RecipeExportSerializer(data=recipe_json, context={'request': request})
if serialized_recipe.is_valid():
recipe = serialized_recipe.save()
recipe.image = File(handle_image(request, File(io.BytesIO(requests.get(recipe_json['image']).content), name='image'), filetype=pathlib.Path(recipe_json['image']).suffix),
name=f'{uuid.uuid4()}_{recipe.pk}{pathlib.Path(recipe_json["image"]).suffix}')
recipe.save()
return Response({
'link': request.build_absolute_uri(reverse('view_recipe', args={recipe.pk}))
}, status=status.HTTP_201_CREATED)
else:
try:
if validators.url(url, public=True):

View File

@@ -95,3 +95,14 @@ To create a superuser you need to
1. execute into the container using `docker-compose exec web_recipes sh`
2. activate the virtual environment `source venv/bin/activate`
3. run `python manage.py createsuperuser` and follow the steps shown.
## Why cant I get support for my manual setup?
Even tough I would love to help everyone get tandoor up and running I have only so much time
that I can spend on this project besides work, family and other life things.
Due to the countless problems that can occur when manually installing I simply do not have
the time to help solving each one.
You can install Tandoor manually but please do not expect me or anyone to help you with that.
As a general advice: If you do it manually do NOT change anything at first and slowly work yourself
to your dream setup.

View File

@@ -31,6 +31,7 @@ Overview of the capabilities of the different integrations.
| ChefTap | ✔️ | ❌ | ❌ |
| Pepperplate | ✔️ | ⌚ | ❌ |
| RecipeSage | ✔️ | ✔️ | ✔️ |
| Rezeptsuite.de | ✔️ | ❌ | ✔️ |
| Domestica | ✔️ | ⌚ | ✔️ |
| MealMaster | ✔️ | ❌ | ❌ |
| RezKonv | ✔️ | ❌ | ❌ |
@@ -233,6 +234,9 @@ Cookmate allows you to export a `.mcb` file which you can simply upload to tando
## RecetteTek
RecetteTek exports are `.rtk` files which can simply be uploaded to tandoor to import all your recipes.
## Rezeptsuite.de
Rezeptsuite.de exports are `.xml` files which can simply be uploaded to tandoor to import all your recipes.
## Melarecipes
Melarecipes provides multiple export formats but only the `MelaRecipes` format can export the complete collection.

View File

@@ -1,5 +1,5 @@
Django==4.1.4
cryptography==38.0.4
Django==4.1.7
cryptography==39.0.1
django-annoying==0.10.6
django-autocomplete-light==3.9.4
django-cleanup==6.0.0
@@ -8,13 +8,13 @@ django-tables2==2.4.1
djangorestframework==3.14.0
drf-writable-nested==0.7.0
django-oauth-toolkit==2.2.0
django-debug-toolbar==3.7.0
django-debug-toolbar==3.8.1
bleach==5.0.1
bleach-allowlist==1.0.3
gunicorn==20.1.0
lxml==4.9.2
Markdown==3.4.1
Pillow==9.3.0
Pillow==9.4.0
psycopg2-binary==2.9.5
python-dotenv==0.21.0
requests==2.28.1
@@ -30,7 +30,7 @@ Jinja2==3.1.2
django-webpack-loader==1.8.0
git+https://github.com/BITSOLVER/django-js-reverse@071e304fd600107bc64bbde6f2491f1fe049ec82
django-allauth==0.52.0
recipe-scrapers==14.24.0
recipe-scrapers==14.30.0
django-scopes==1.2.0.post1
pytest==7.2.0
pytest-django==4.5.2

View File

@@ -13,6 +13,7 @@
"@popperjs/core": "^2.11.6",
"@riophae/vue-treeselect": "^0.4.0",
"@vue/cli": "^5.0.8",
"@vue/composition-api": "1.7.1",
"axios": "^1.2.0",
"babel": "^6.23.0",
"babel-core": "^6.26.3",
@@ -25,6 +26,7 @@
"lodash": "^4.17.21",
"mavon-editor": "^2.10.4",
"moment": "^2.29.4",
"pinia": "^2.0.30",
"prismjs": "^1.29.0",
"string-similarity": "^4.0.4",
"vue": "^2.6.14",
@@ -42,8 +44,8 @@
"vue-template-compiler": "2.6.14",
"vue2-touch-events": "^3.2.2",
"vuedraggable": "^2.24.3",
"vuex": "^3.6.0",
"workbox-webpack-plugin": "^6.5.4"
"workbox-webpack-plugin": "^6.5.4",
"workbox-window": "^6.5.4"
},
"devDependencies": {
"@kazupon/vue-i18n-loader": "^0.5.0",
@@ -62,6 +64,7 @@
"typescript": "~4.9.3",
"vue-cli-plugin-i18n": "^2.3.1",
"webpack-bundle-tracker": "1.8.0",
"workbox-background-sync": "^6.5.4",
"workbox-expiration": "^6.5.4",
"workbox-navigation-preload": "^6.5.4",
"workbox-precaching": "^6.5.4",

View File

@@ -18,7 +18,8 @@
</div>
</div>
</div>
<div class="mb-3" v-for="book in filteredBooks" :key="book.id">
<div style="padding-bottom: 55px">
<div class="mb-3" v-for="book in filteredBooks" :key="book.id">
<div class="row">
<div class="col-md-12">
<b-card class="d-flex flex-column" v-hover v-on:click="openBook(book.id)">
@@ -53,7 +54,21 @@
@reload="openBook(current_book, true)"
></cookbook-slider>
</transition>
</div>
</div>
<bottom-navigation-bar>
<template #custom_create_functions>
<div class="dropdown-divider" ></div>
<h6 class="dropdown-header">{{ $t('Books')}}</h6>
<a class="dropdown-item" @click="createNew()"><i
class="fa fa-book"></i> {{$t("Create")}}</a>
</template>
</bottom-navigation-bar>
</div>
</template>
@@ -66,13 +81,14 @@ import { ApiApiFactory } from "@/utils/openapi/api"
import CookbookSlider from "@/components/CookbookSlider"
import LoadingSpinner from "@/components/LoadingSpinner"
import { StandardToasts, ApiMixin } from "@/utils/utils"
import BottomNavigationBar from "@/components/BottomNavigationBar.vue";
Vue.use(BootstrapVue)
export default {
name: "CookbookView",
mixins: [ApiMixin],
components: { LoadingSpinner, CookbookSlider },
components: { LoadingSpinner, CookbookSlider, BottomNavigationBar },
data() {
return {
cookbooks: [],

View File

@@ -1,6 +1,7 @@
import Vue from 'vue'
import App from './CookbookView.vue'
import i18n from '@/i18n'
import {createPinia, PiniaVuePlugin} from "pinia";
Vue.config.productionTip = false
@@ -11,8 +12,11 @@ if (process.env.NODE_ENV === 'development') {
}
export default __webpack_public_path__ = publicPath // eslint-disable-line
Vue.use(PiniaVuePlugin)
const pinia = createPinia()
new Vue({
pinia,
i18n,
render: h => h(App),
}).$mount('#app')

View File

@@ -1,6 +1,7 @@
import Vue from 'vue'
import App from './ExportResponseView.vue'
import i18n from '@/i18n'
import {createPinia, PiniaVuePlugin} from "pinia";
Vue.config.productionTip = false
@@ -11,8 +12,11 @@ if (process.env.NODE_ENV === 'development') {
}
export default __webpack_public_path__ = publicPath // eslint-disable-line
Vue.use(PiniaVuePlugin)
const pinia = createPinia()
new Vue({
pinia,
i18n,
render: h => h(App),
}).$mount('#app')

View File

@@ -1,6 +1,7 @@
import Vue from 'vue'
import App from './ExportView.vue'
import i18n from '@/i18n'
import {createPinia, PiniaVuePlugin} from "pinia";
Vue.config.productionTip = false
@@ -11,8 +12,11 @@ if (process.env.NODE_ENV === 'development') {
}
export default __webpack_public_path__ = publicPath // eslint-disable-line
Vue.use(PiniaVuePlugin)
const pinia = createPinia()
new Vue({
pinia,
i18n,
render: h => h(App),
}).$mount('#app')

View File

@@ -1,6 +1,7 @@
import Vue from 'vue'
import App from './ImportResponseView.vue'
import i18n from '@/i18n'
import {createPinia, PiniaVuePlugin} from "pinia";
Vue.config.productionTip = false
@@ -11,8 +12,11 @@ if (process.env.NODE_ENV === 'development') {
}
export default __webpack_public_path__ = publicPath // eslint-disable-line
Vue.use(PiniaVuePlugin)
const pinia = createPinia()
new Vue({
pinia,
i18n,
render: h => h(App),
}).$mount('#app')

View File

@@ -24,8 +24,11 @@
<div class="row justify-content-center">
<div class="col-12 justify-content-cente">
<b-checkbox v-model="import_multiple" switch><span
v-if="import_multiple"><i class="far fa-copy fa-fw"></i> {{ $t('Multiple') }}</span><span
v-if="!import_multiple"><i class="far fa-file fa-fw"></i> {{ $t('Single') }}</span></b-checkbox>
v-if="import_multiple"><i
class="far fa-copy fa-fw"></i> {{ $t('Multiple') }}</span><span
v-if="!import_multiple"><i
class="far fa-file fa-fw"></i> {{ $t('Single') }}</span>
</b-checkbox>
</div>
</div>
<b-input-group class="mt-2" :class="{ bounce: empty_input }"
@@ -52,23 +55,23 @@
</b-button>
<!-- recent imports, nice for testing/development -->
<!-- <div class="row mt-2"> -->
<!-- <div class="col col-md-12">-->
<!-- <div v-if="!import_multiple">-->
<!-- <a href="#" @click="clearRecentImports()">Clear recent-->
<!-- imports</a>-->
<!-- <ul>-->
<!-- <li v-for="x in recent_urls" v-bind:key="x">-->
<!-- <a href="#"-->
<!-- @click="loadRecipe(x, false, undefined)">{{-->
<!-- x-->
<!-- }}</a>-->
<!-- </li>-->
<!-- </ul>-->
<!-- <div class="row mt-2"> -->
<!-- <div class="col col-md-12">-->
<!-- <div v-if="!import_multiple">-->
<!-- <a href="#" @click="clearRecentImports()">Clear recent-->
<!-- imports</a>-->
<!-- <ul>-->
<!-- <li v-for="x in recent_urls" v-bind:key="x">-->
<!-- <a href="#"-->
<!-- @click="loadRecipe(x, false, undefined)">{{-->
<!-- x-->
<!-- }}</a>-->
<!-- </li>-->
<!-- </ul>-->
<!-- </div>-->
<!-- </div>-->
<!-- </div>-->
<!-- </div>-->
<!-- </div>-->
<!-- </div>-->
</div>
</div>
@@ -204,7 +207,7 @@
v-if="!import_multiple">
<recipe-card :recipe="recipe_json" :detailed="false"
:show_context_menu="false" :use_plural="use_plural"
:show_context_menu="false"
></recipe-card>
</b-col>
<b-col>
@@ -238,17 +241,22 @@
</b-row>
</b-card-body>
<b-card-footer class="text-center">
<div class="d-flex justify-content-center mb-3" v-if="import_loading">
<b-spinner variant="primary"></b-spinner>
</div>
<b-button-group>
<b-button @click="importRecipe('view')" v-if="!import_multiple">Import &
<b-button @click="importRecipe('view')" v-if="!import_multiple"
:disabled="import_loading">Import &
View
</b-button> <!-- TODO localize -->
<b-button @click="importRecipe('edit')" variant="success"
v-if="!import_multiple">Import & Edit
v-if="!import_multiple" :disabled="import_loading">Import & Edit
</b-button>
<b-button @click="importRecipe('import')" v-if="!import_multiple">Import &
<b-button @click="importRecipe('import')" v-if="!import_multiple"
:disabled="import_loading">Import &
Restart
</b-button>
<b-button @click="location.reload()">Restart
<b-button @click="location.reload()" :disabled="import_loading">Restart
</b-button>
</b-button-group>
</b-card-footer>
@@ -462,6 +470,7 @@ export default {
source_data: '',
recipe_json: undefined,
use_plural: false,
import_loading: false,
// recipe_html: undefined,
// recipe_tree: undefined,
recipe_images: [],
@@ -495,6 +504,13 @@ export default {
apiClient.retrieveSpace(window.ACTIVE_SPACE_ID).then(r => {
this.use_plural = r.data.use_plural
})
let urlParams = new URLSearchParams(window.location.search)
if (urlParams.has("url")) {
this.website_url = urlParams.get('url')
this.loadRecipe(this.website_url)
}
},
methods: {
/**
@@ -504,6 +520,7 @@ export default {
* @param silent do not show any messages for imports
*/
importRecipe: function (action, data, silent) {
this.import_loading = true
if (this.recipe_json !== undefined) {
this.$set(this.recipe_json, 'keywords', this.recipe_json.keywords.filter(k => k.show))
}
@@ -528,12 +545,14 @@ export default {
if (recipe_json.source_url !== '') {
this.failed_imports.push(recipe_json.source_url)
}
this.import_loading = false
if (!silent) {
StandardToasts.makeStandardToast(this, StandardToasts.FAIL_CREATE)
}
})
} else {
console.log('cant import recipe without data')
this.import_loading = false
if (!silent) {
StandardToasts.makeStandardToast(this, StandardToasts.FAIL_CREATE)
}
@@ -563,6 +582,7 @@ export default {
this.imported_recipes.push(recipe)
break;
case 'nothing':
this.import_loading = false
break;
}
},
@@ -614,6 +634,11 @@ export default {
}
return axios.post(resolveDjangoUrl('api_recipe_from_source'), payload,).then((response) => {
if (response.status === 201 && 'link' in response.data) {
window.location = response.data.link
return
}
this.loading = false
this.recipe_json = response.data['recipe_json'];

View File

@@ -28,7 +28,7 @@
<b-badge variant="secondary" v-if="i.unit">{{ i.unit.name }}</b-badge>
<b-badge variant="info" v-if="i.food">{{ i.food.name }}</b-badge>
<i>{{ i.original_text }}</i>
<b-button @click="current_edit_ingredient = i" v-b-modal.ingredient_edit_modal class="float-right btn-sm"><i class="fas fa-pencil-alt"></i></b-button>
<b-button @click="prepareIngredientEditModal(s,i)" v-b-modal.ingredient_edit_modal class="float-right btn-sm"><i class="fas fa-pencil-alt"></i></b-button>
</b-list-group-item>
</draggable>
</div>
@@ -62,25 +62,37 @@
</div>
</div>
<b-modal id="ingredient_edit_modal" :title="$t('Edit')" ok-only>
<b-modal id="ingredient_edit_modal" :title="$t('Edit')">
<div v-if="current_edit_ingredient !== null">
<b-form-group v-bind:label="$t('Original_Text')" class="mb-3">
<b-form-input v-model="current_edit_ingredient.original_text" type="text" disabled></b-form-input>
</b-form-group>
<b-form-group v-bind:label="$t('Amount')" class="mb-3">
<b-form-input v-model="current_edit_ingredient.amount" type="number" ></b-form-input>
<b-form-input v-model.number="current_edit_ingredient.amount" type="number"></b-form-input>
</b-form-group>
<b-form-group v-bind:label="$t('Unit')" class="mb-3">
<b-form-input v-model="current_edit_ingredient.unit.name" type="text" ></b-form-input>
<b-form-group v-bind:label="$t('Unit')" class="mb-3" v-if="current_edit_ingredient.unit !== null">
<b-form-input v-model="current_edit_ingredient.unit.name" type="text"></b-form-input>
</b-form-group>
<b-form-group v-bind:label="$t('Food')" class="mb-3">
<b-form-input v-model="current_edit_ingredient.food.name" type="text" ></b-form-input>
<b-form-input v-model="current_edit_ingredient.food.name" type="text"></b-form-input>
</b-form-group>
<b-form-group v-bind:label="$t('Note')" class="mb-3">
<b-form-input v-model="current_edit_ingredient.note" type="text"></b-form-input>
</b-form-group>
</div>
<template v-slot:modal-footer>
<div class="row w-100">
<div class="col-auto justify-content-end">
<b-button class="mx-1" @click="destroyIngredientEditModal()">{{ $t('Ok') }}</b-button>
<b-button class="mx-1" @click="removeIngredient(current_edit_step,current_edit_ingredient);destroyIngredientEditModal()" variant="danger">{{ $t('Delete') }}</b-button>
</div>
</div>
</template>
</b-modal>
</div>
</div>
@@ -104,6 +116,7 @@ export default {
return {
recipe_json: undefined,
current_edit_ingredient: null,
current_edit_step: null,
}
},
watch: {
@@ -202,7 +215,50 @@ export default {
found = true
}
})
},
/**
* Prepare variable that holds currently edited ingredient for modal to manipulate it
* add default placeholder for food/unit in case it is not present, so it can be edited as well
* @param ingredient
*/
prepareIngredientEditModal: function (step, ingredient) {
if (ingredient.unit === null) {
ingredient.unit = {
"name": ""
}
}
if (ingredient.food === null) {
ingredient.food = {
"name": ""
}
}
this.current_edit_ingredient = ingredient
this.current_edit_step = step
},
/**
* can be called to remove an ingredient from the given step
* @param step step to remove ingredient from
* @param ingredient ingredient to remove
*/
removeIngredient: function (step, ingredient) {
step.ingredients = step.ingredients.filter((i) => i !== ingredient)
},
/**
* cleanup method called to close modal
* closes modal UI and cleanups variables
*/
destroyIngredientEditModal: function () {
this.$bvModal.hide('ingredient_edit_modal')
if (this.current_edit_ingredient.unit.name === ''){
this.current_edit_ingredient.unit = null
}
if (this.current_edit_ingredient.food.name === ''){
this.current_edit_ingredient.food = null
}
this.current_edit_ingredient = null
this.current_edit_step = null
}
}
}
</script>

View File

@@ -1,6 +1,7 @@
import Vue from 'vue'
import App from './ImportView.vue'
import i18n from '@/i18n'
import {createPinia, PiniaVuePlugin} from "pinia";
Vue.config.productionTip = false
@@ -11,8 +12,11 @@ if (process.env.NODE_ENV === 'development') {
}
export default __webpack_public_path__ = publicPath // eslint-disable-line
Vue.use(PiniaVuePlugin)
const pinia = createPinia()
new Vue({
pinia,
i18n,
render: h => h(App),
}).$mount('#app')

View File

@@ -1,6 +1,7 @@
import Vue from 'vue'
import App from './IngredientEditorView.vue'
import i18n from '@/i18n'
import {createPinia, PiniaVuePlugin} from "pinia";
Vue.config.productionTip = false
@@ -11,8 +12,11 @@ if (process.env.NODE_ENV === 'development') {
}
export default __webpack_public_path__ = publicPath // eslint-disable-line
Vue.use(PiniaVuePlugin)
const pinia = createPinia()
new Vue({
pinia,
i18n,
render: h => h(App),
}).$mount('#app')

View File

@@ -2,7 +2,7 @@
<div>
<b-tabs content-class="mt-3" v-model="current_tab">
<b-tab :title="$t('Planner')" active>
<div class="row calender-row">
<div class="row calender-row d-none d-lg-block">
<div class="col-12 calender-parent">
<calendar-view
:show-date="showDate"
@@ -48,6 +48,79 @@
</calendar-view>
</div>
</div>
<div class="row d-block d-lg-none">
<div>
<div class="col-12">
<div class="col-12 d-flex justify-content-center mt-2">
<b-button-toolbar key-nav aria-label="Toolbar with button groups">
<b-button-group class="mx-1">
<b-button v-html="'<<'" class="p-2 pr-3 pl-3"
@click="setShowDate($refs.header.headerProps.previousPeriod)"></b-button>
</b-button-group>
<b-button-group class="mx-1">
<b-button @click="setShowDate($refs.header.headerProps.currentPeriod)"><i
class="fas fa-home"></i></b-button>
<b-form-datepicker right button-only button-variant="secondary" @context="datePickerChanged"></b-form-datepicker>
</b-button-group>
<b-button-group class="mx-1">
<b-button v-html="'>>'" class="p-2 pr-3 pl-3"
@click="setShowDate($refs.header.headerProps.nextPeriod)"></b-button>
</b-button-group>
</b-button-toolbar>
</div>
</div>
<div class="col-12 mt-2" style="padding-bottom: 60px">
<div v-for="day in mobileSimpleGrid" v-bind:key="day.day">
<b-list-group>
<b-list-group-item>
<div class="d-flex flex-row align-middle">
<h6 class="mb-0 mt-1 align-middle">{{ day.date_label }}</h6>
<div class="flex-grow-1 text-right">
<b-button class="btn-sm btn-outline-primary" @click="showMealPlanEditModal(null, day.create_default_date)"><i
class="fa fa-plus"></i></b-button>
</div>
</div>
</b-list-group-item>
<b-list-group-item v-for="plan in day.plan_entries" v-bind:key="plan.entry.id" >
<div class="d-flex flex-row align-items-center">
<div>
<b-img style="height: 50px; width: 50px; object-fit: cover"
:src="plan.entry.recipe.image" rounded="circle" v-if="plan.entry.recipe?.image"></b-img>
<b-img style="height: 50px; width: 50px; object-fit: cover"
:src="image_placeholder" rounded="circle" v-else></b-img>
</div>
<div class="flex-grow-1 ml-2"
style="text-overflow: ellipsis; overflow-wrap: anywhere;">
<span class="two-row-text">
<a :href="resolveDjangoUrl('view_recipe', plan.entry.recipe.id)" v-if="plan.entry.recipe">{{ plan.entry.recipe.name }}</a>
<span v-else>{{ plan.entry.title }}</span> <br/>
</span>
<span v-if="plan.entry.note" class="two-row-text">
<small>{{ plan.entry.note }}</small> <br/>
</span>
<small class="text-muted">
<span v-if="plan.entry.shopping" class="font-light"><i class="fas fa-shopping-cart fa-xs "/></span>
{{ plan.entry.meal_type_name }}
<span v-if="plan.entry.recipe">
- <i class="fa fa-clock"></i> {{ plan.entry.recipe.working_time + plan.entry.recipe.waiting_time }} {{ $t('min') }}
</span>
</small>
</div>
<div class="hover-button">
<a class="pr-2" @click.stop="openContextMenu($event, {originalItem: plan})"><i class="fas fa-ellipsis-v"></i></a>
</div>
</div>
</b-list-group-item>
</b-list-group>
</div>
</div>
</div>
</div>
</b-tab>
<b-tab :title="$t('Settings')">
<div class="row mt-3">
@@ -166,7 +239,7 @@
<ContextMenuItem
@click="
$refs.menu.close()
moveEntryLeft(contextData)
moveEntryLeft(contextData.originalItem)
"
>
<a class="dropdown-item p-2" href="javascript:void(0)"><i class="fas fa-arrow-left"></i>
@@ -175,7 +248,7 @@
<ContextMenuItem
@click="
$refs.menu.close()
moveEntryRight(contextData)
moveEntryRight(contextData.originalItem)
"
>
<a class="dropdown-item p-2" href="javascript:void(0)"><i class="fas fa-arrow-right"></i>
@@ -192,7 +265,7 @@
<ContextMenuItem
@click="
$refs.menu.close()
deleteEntry(contextData)
deleteEntry(contextData.originalItem)
"
>
<a class="dropdown-item p-2 text-danger" href="javascript:void(0)"><i class="fas fa-trash"></i>
@@ -203,53 +276,28 @@
<meal-plan-edit-modal
:entry="entryEditing"
:modal_title="modal_title"
:edit_modal_show="edit_modal_show"
@save-entry="editEntry"
@delete-entry="deleteEntry"
:create_date="mealplan_default_date"
@reload-meal-types="refreshMealTypes"
></meal-plan-edit-modal>
<transition name="slide-fade">
<div class="row fixed-bottom p-2 b-1 border-top text-center" style="background: rgba(255, 255, 255, 0.6)"
v-if="current_tab === 0">
<div class="col-md-3 col-6 mb-1 mb-md-0">
<button class="btn btn-block btn-success shadow-none" @click="createEntryClick(new Date())"><i
class="fas fa-calendar-plus"></i> {{ $t("Create") }}
</button>
</div>
<div class="col-md-3 col-6 mb-1 mb-md-0">
<a class="btn btn-block btn-primary shadow-none" :href="iCalUrl"
><i class="fas fa-download"></i>
{{ $t("Export_To_ICal") }}
</a>
</div>
<div class="col-md-3 col-6 mb-1 mb-md-0">
<button class="btn btn-block btn-primary shadow-none disabled" v-b-tooltip.focus.top
:title="$t('Coming_Soon')">
{{ $t("Auto_Planner") }}
</button>
</div>
<div class="col-12 d-flex justify-content-center mt-2 d-block d-md-none">
<b-button-toolbar key-nav aria-label="Toolbar with button groups">
<b-button-group class="mx-1">
<b-button v-html="'<<'" class="p-2 pr-3 pl-3"
@click="setShowDate($refs.header.headerProps.previousPeriod)"></b-button>
<b-button v-html="'<'" @click="setStartingDay(-1)" class="p-2 pr-3 pl-3"></b-button>
</b-button-group>
<b-button-group class="mx-1">
<b-button @click="setShowDate($refs.header.headerProps.currentPeriod)"><i
class="fas fa-home"></i></b-button>
<b-form-datepicker button-only button-variant="secondary"></b-form-datepicker>
</b-button-group>
<b-button-group class="mx-1">
<b-button v-html="'>'" @click="setStartingDay(1)" class="p-2 pr-3 pl-3"></b-button>
<b-button v-html="'>>'" class="p-2 pr-3 pl-3"
@click="setShowDate($refs.header.headerProps.nextPeriod)"></b-button>
</b-button-group>
</b-button-toolbar>
</div>
<div class="row d-none d-lg-block">
<div class="col-12 float-right">
<button class="btn btn-success shadow-none" @click="createEntryClick(new Date())"><i
class="fas fa-calendar-plus"></i> {{ $t("Create") }}
</button>
<a class="btn btn-primary shadow-none" :href="iCalUrl"><i class="fas fa-download"></i>
{{ $t("Export_To_ICal") }}
</a>
</div>
</transition>
</div>
<bottom-navigation-bar :create_links="[{label:$t('Export_To_ICal'), url: iCalUrl, icon:'fas fa-download'}]">
<template #custom_create_functions>
<h6 class="dropdown-header">{{ $t('Meal_Plan')}}</h6>
<a class="dropdown-item" @click="createEntryClick(new Date())"><i
class="fas fa-calendar-plus fa-fw"></i> {{ $t("Create") }}</a>
</template>
</bottom-navigation-bar>
</div>
</template>
@@ -272,6 +320,8 @@ import VueCookies from "vue-cookies"
import {ApiMixin, StandardToasts, ResolveUrlMixin} from "@/utils/utils"
import {CalendarView, CalendarMathMixin} from "vue-simple-calendar/src/components/bundle"
import {ApiApiFactory} from "@/utils/openapi/api"
import BottomNavigationBar from "@/components/BottomNavigationBar.vue";
import {useMealPlanStore} from "@/stores/MealPlanStore";
const {makeToast} = require("@/utils/utils")
@@ -292,6 +342,7 @@ export default {
MealPlanCalenderHeader,
EmojiInput,
draggable,
BottomNavigationBar,
},
mixins: [CalendarMathMixin, ApiMixin, ResolveUrlMixin],
data: function () {
@@ -319,29 +370,18 @@ export default {
{text: this.$t("Year"), value: "year"},
],
displayPeriodCount: [1, 2, 3],
entryEditing: {
date: null,
id: -1,
meal_type: null,
note: "",
note_markdown: "",
recipe: null,
servings: 1,
shared: [],
title: "",
title_placeholder: this.$t("Title"),
},
},
shopping_list: [],
current_period: null,
entryEditing: {},
edit_modal_show: false,
entryEditing: null,
mealplan_default_date: null,
ical_url: window.ICAL_URL,
image_placeholder: window.IMAGE_PLACEHOLDER,
}
},
computed: {
modal_title: function () {
if (this.entryEditing.id === -1) {
if (this.entryEditing === null || this.entryEditing?.id === -1) {
return this.$t("Create_Meal_Plan_Entry")
} else {
return this.$t("Edit_Meal_Plan_Entry")
@@ -349,7 +389,7 @@ export default {
},
plan_items: function () {
let items = []
this.plan_entries.forEach((entry) => {
useMealPlanStore().plan_list.forEach((entry) => {
items.push(this.buildItem(entry))
})
return items
@@ -383,6 +423,22 @@ export default {
return ""
}
},
mobileSimpleGrid() {
let grid = []
if (this.current_period !== null) {
for (const x of Array(7).keys()) {
let moment_date = moment(this.current_period.periodStart).add(x, "d")
grid.push({
date: moment_date,
create_default_date: moment_date.format("YYYY-MM-DD"), // improve meal plan edit modal to do formatting itself and accept dates
date_label: moment_date.format('ddd DD.MM'),
plan_entries: this.plan_items.filter((m) => moment(m.startDate).isSame(moment_date, 'day'))
})
}
}
return grid
}
},
mounted() {
this.$nextTick(function () {
@@ -392,6 +448,7 @@ export default {
})
this.$root.$on("change", this.updateEmoji)
this.$i18n.locale = window.CUSTOM_LOCALE
moment.locale(window.CUSTOM_LOCALE)
},
watch: {
settings: {
@@ -489,33 +546,26 @@ export default {
}
})
},
editEntry(edit_entry) {
if (edit_entry.id !== -1) {
this.plan_entries.forEach((entry, index) => {
if (entry.id === edit_entry.id) {
this.$set(this.plan_entries, index, edit_entry)
this.saveEntry(this.plan_entries[index])
}
})
} else {
this.createEntry(edit_entry)
}
datePickerChanged(ctx) {
this.setShowDate(ctx.selectedDate)
},
setShowDate(d) {
this.showDate = d
},
createEntryClick(data) {
this.entryEditing = this.options.entryEditing
this.entryEditing.date = moment(data).format("YYYY-MM-DD")
this.$bvModal.show(`edit-modal`)
this.mealplan_default_date = moment(data).format("YYYY-MM-DD")
this.entryEditing = null
this.$nextTick(function () {
this.$bvModal.show(`id_meal_plan_edit_modal`)
})
},
findEntry(id) {
return this.plan_entries.filter((entry) => {
return useMealPlanStore().plan_list.filter((entry) => {
return entry.id === id
})[0]
},
moveEntry(null_object, target_date, drag_event) {
this.plan_entries.forEach((entry) => {
useMealPlanStore().plan_list.forEach((entry) => {
if (entry.id === this.dragged_item.id) {
if (drag_event.ctrlKey) {
let new_entry = Object.assign({}, entry)
@@ -529,7 +579,7 @@ export default {
})
},
moveEntryLeft(data) {
this.plan_entries.forEach((entry) => {
useMealPlanStore().plan_list.forEach((entry) => {
if (entry.id === data.id) {
entry.date = moment(entry.date).subtract(1, "d")
this.saveEntry(entry)
@@ -537,7 +587,7 @@ export default {
})
},
moveEntryRight(data) {
this.plan_entries.forEach((entry) => {
useMealPlanStore().plan_list.forEach((entry) => {
if (entry.id === data.id) {
entry.date = moment(entry.date).add(1, "d")
this.saveEntry(entry)
@@ -545,20 +595,7 @@ export default {
})
},
deleteEntry(data) {
this.plan_entries.forEach((entry, index, list) => {
if (entry.id === data.id) {
let apiClient = new ApiApiFactory()
apiClient
.destroyMealPlan(entry.id)
.then((e) => {
list.splice(index, 1)
})
.catch((err) => {
StandardToasts.makeStandardToast(this, StandardToasts.FAIL_UPDATE, err)
})
}
})
useMealPlanStore().deleteObject(data)
},
entryClick(data) {
let entry = this.findEntry(data.id)
@@ -568,7 +605,7 @@ export default {
this.$refs.menu.open($event, value)
},
openEntryEdit(entry) {
this.$bvModal.show(`edit-modal`)
this.$bvModal.show(`id_meal_plan_edit_modal`)
this.entryEditing = entry
this.entryEditing.date = moment(entry.date).format("YYYY-MM-DD")
if (this.entryEditing.recipe != null) {
@@ -577,18 +614,9 @@ export default {
},
periodChangedCallback(date) {
this.current_period = date
let apiClient = new ApiApiFactory()
apiClient
.listMealPlans({
query: {
from_date: moment(date.periodStart).format("YYYY-MM-DD"),
to_date: moment(date.periodEnd).format("YYYY-MM-DD"),
},
})
.then((result) => {
this.plan_entries = result.data
})
useMealPlanStore().refreshFromAPI(moment(date.periodStart).format("YYYY-MM-DD"), moment(date.periodEnd).format("YYYY-MM-DD"))
this.refreshMealTypes()
},
refreshMealTypes() {
@@ -604,25 +632,11 @@ export default {
saveEntry(entry) {
entry.date = moment(entry.date).format("YYYY-MM-DD")
let apiClient = new ApiApiFactory()
apiClient.updateMealPlan(entry.id, entry).catch((err) => {
StandardToasts.makeStandardToast(this, StandardToasts.FAIL_UPDATE, err)
})
useMealPlanStore().updateObject(entry)
},
createEntry(entry) {
entry.date = moment(entry.date).format("YYYY-MM-DD")
let apiClient = new ApiApiFactory()
apiClient
.createMealPlan(entry)
.catch((err) => {
StandardToasts.makeStandardToast(this, StandardToasts.FAIL_UPDATE, err)
})
.then((entry_result) => {
this.plan_entries.push(entry_result.data)
})
useMealPlanStore().createObject(entry)
},
buildItem(plan_entry) {
//dirty hack to order items within a day
@@ -634,6 +648,15 @@ export default {
entry: plan_entry,
}
},
showMealPlanEditModal: function (entry, date) {
this.mealplan_default_date = date
this.entryEditing = entry
this.$nextTick(function () {
this.$bvModal.show(`id_meal_plan_edit_modal`)
})
}
},
directives: {
hover: {
@@ -651,6 +674,10 @@ export default {
</script>
<style>
#id_base_container {
margin-top: 12px
}
.slide-fade-enter-active {
transition: all 0.3s ease;
}

View File

@@ -1,6 +1,7 @@
import Vue from 'vue'
import App from './MealPlanView.vue'
import i18n from '@/i18n'
import {createPinia, PiniaVuePlugin} from "pinia";
Vue.config.productionTip = false
@@ -11,7 +12,11 @@ if (process.env.NODE_ENV === 'development') {
}
export default __webpack_public_path__ = publicPath // eslint-disable-line
Vue.use(PiniaVuePlugin)
const pinia = createPinia()
new Vue({
pinia,
i18n,
render: h => h(App),
}).$mount('#app')

View File

@@ -41,7 +41,6 @@
<!-- model isn't paginated and loads in one API call -->
<div v-if="!paginated">
<generic-horizontal-card v-for="i in items_left" v-bind:key="i.id" :item="i"
:use_plural="use_plural"
:model="this_model" @item-action="startAction($event, 'left')"
@finish-action="finishAction"/>
</div>
@@ -51,7 +50,6 @@
<template v-slot:cards>
<generic-horizontal-card v-for="i in items_left" v-bind:key="i.id" :item="i"
:model="this_model"
:use_plural="use_plural"
@item-action="startAction($event, 'left')"
@finish-action="finishAction"/>
</template>
@@ -63,7 +61,6 @@
<template v-slot:cards>
<generic-horizontal-card v-for="i in items_right" v-bind:key="i.id" :item="i"
:model="this_model"
:use_plural="use_plural"
@item-action="startAction($event, 'right')"
@finish-action="finishAction"/>
</template>

View File

@@ -1,6 +1,7 @@
import Vue from 'vue'
import App from './ModelListView'
import i18n from '@/i18n'
import {createPinia, PiniaVuePlugin} from "pinia";
Vue.config.productionTip = false
@@ -11,8 +12,11 @@ if (process.env.NODE_ENV === 'development') {
}
export default __webpack_public_path__ = publicPath // eslint-disable-line
Vue.use(PiniaVuePlugin)
const pinia = createPinia()
new Vue({
pinia,
i18n,
render: h => h(App),
}).$mount('#app')

View File

@@ -1,6 +1,7 @@
import Vue from 'vue'
import App from './OfflineView.vue'
import i18n from "@/i18n";
import {createPinia, PiniaVuePlugin} from "pinia";
Vue.config.productionTip = false
@@ -11,8 +12,11 @@ if (process.env.NODE_ENV === 'development') {
}
export default __webpack_public_path__ = publicPath // eslint-disable-line
Vue.use(PiniaVuePlugin)
const pinia = createPinia()
new Vue({
pinia,
i18n,
render: h => h(App),
}).$mount('#app')

View File

@@ -1,6 +1,7 @@
import Vue from 'vue'
import App from './ProfileView.vue'
import i18n from '@/i18n'
import {createPinia, PiniaVuePlugin} from "pinia";
Vue.config.productionTip = false
@@ -11,8 +12,11 @@ if (process.env.NODE_ENV === 'development') {
}
export default __webpack_public_path__ = publicPath // eslint-disable-line
Vue.use(PiniaVuePlugin)
const pinia = createPinia()
new Vue({
pinia,
i18n,
render: h => h(App),
}).$mount('#app')

View File

@@ -572,7 +572,7 @@
{{ $t("Enable_Amount") }}
</button>
<template v-if="use_plural">
<button type="button" class="dropdown-item"
v-if="!ingredient.always_use_plural_unit"
@click="ingredient.always_use_plural_unit = true">
@@ -600,7 +600,7 @@
<i class="fas fa-filter fa-fw"></i>
{{ $t("Use_Plural_Food_Simple") }}
</button>
</template>
<button type="button" class="dropdown-item"
@click="copyTemplateReference(index, ingredient)">

View File

@@ -1,6 +1,7 @@
import Vue from 'vue'
import App from './RecipeEditView'
import i18n from '@/i18n'
import {createPinia, PiniaVuePlugin} from "pinia";
Vue.config.productionTip = false
@@ -11,8 +12,11 @@ if (process.env.NODE_ENV === 'development') {
}
export default __webpack_public_path__ = publicPath // eslint-disable-line
Vue.use(PiniaVuePlugin)
const pinia = createPinia()
new Vue({
pinia,
i18n,
render: h => h(App),
}).$mount('#app')

View File

@@ -1,5 +1,5 @@
<template>
<div id="app" style="margin-bottom: 4vh">
<div id="app" style="padding-bottom: 60px">
<RecipeSwitcher ref="ref_recipe_switcher"/>
<div class="row">
<div class="col-12 col-xl-10 col-lg-10 offset-xl-1 offset-lg-1">
@@ -90,7 +90,7 @@
<b-form-group v-if="ui.show_meal_plan"
v-bind:label="$t('Meal_Plan_Days')"
label-for="popover-input-5" label-cols="8" class="mb-1">
<b-form-input type="number" v-model="ui.meal_plan_days"
<b-form-input type="number" v-model.number="ui.meal_plan_days"
id="popover-input-5" size="sm"
class="mt-1"></b-form-input>
</b-form-group>
@@ -797,8 +797,9 @@
<div class="col-12 col-xl-10 col-lg-10 offset-xl-1 offset-lg-1">
<div style="overflow-x:visible; overflow-y: hidden;white-space: nowrap;">
<b-dropdown id="sortby" :text="sortByLabel" variant="outline-primary" size="sm" style="overflow-y: visible; overflow-x: visible; position: static"
class="shadow-none" toggle-class="text-decoration-none" >
<b-dropdown id="sortby" :text="sortByLabel" variant="outline-primary" size="sm"
style="overflow-y: visible; overflow-x: visible; position: static"
class="shadow-none" toggle-class="text-decoration-none">
<div v-for="o in sortOptions" :key="o.id">
<b-dropdown-item
v-on:click="
@@ -812,7 +813,7 @@
</b-dropdown>
<b-button variant="outline-primary" size="sm" class="shadow-none ml-1"
@click="resetSearch()"><i class="fas fa-file-alt"></i> {{
@click="resetSearch()" v-if="searchFiltered()"><i class="fas fa-file-alt"></i> {{
search.pagination_page
}}/{{ Math.ceil(pagination_count / ui.page_size) }} {{ $t("Reset") }} <i
class="fas fa-times-circle"></i>
@@ -828,34 +829,92 @@
</div>
</div>
<template v-if="!searchFiltered() && ui.show_meal_plan && meal_plan_grid.length > 0">
<hr/>
<div class="row">
<div class="col col-md-12">
<div
style="display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); column-gap: 0.5rem;row-gap: 0.5rem; grid-auto-rows: max-content; ">
<div v-for="day in meal_plan_grid" v-bind:key="day.day" :class="{'d-none d-sm-block': day.plan_entries.length === 0}">
<b-list-group >
<b-list-group-item class="hover-div pb-0">
<div class="d-flex flex-row align-items-center">
<div>
<h6>{{ day.date_label }}</h6>
</div>
<div class="flex-grow-1 text-right">
<b-button class="hover-button btn-outline-primary btn-sm" @click="showMealPlanEditModal(null, day.create_default_date)"><i
class="fa fa-plus"></i></b-button>
</div>
</div>
</b-list-group-item>
<b-list-group-item v-for="plan in day.plan_entries" v-bind:key="plan.id" class="hover-div">
<div class="d-flex flex-row align-items-center">
<div>
<b-img style="height: 50px; width: 50px; object-fit: cover"
:src="plan.recipe.image" rounded="circle" v-if="plan.recipe?.image"></b-img>
<b-img style="height: 50px; width: 50px; object-fit: cover"
:src="image_placeholder" rounded="circle" v-else></b-img>
</div>
<div class="flex-grow-1 ml-2"
style="text-overflow: ellipsis; overflow-wrap: anywhere;">
<span class="two-row-text">
<a :href="resolveDjangoUrl('view_recipe', plan.recipe.id)" v-if="plan.recipe">{{ plan.recipe.name }}</a>
<span v-else>{{ plan.title }}</span>
</span>
</div>
<div class="hover-button">
<b-button @click="showMealPlanEditModal(plan,null)" class="btn-outline-primary btn-sm"><i class="fas fa-pencil-alt"></i></b-button>
</div>
</div>
</b-list-group-item>
</b-list-group>
</div>
</div>
</div>
</div>
<hr/>
</template>
<div v-if="recipes.length > 0" class="mt-4">
<div class="row">
<div class="col col-md-12">
<div
style="display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); grid-gap: 0.4rem">
<template v-if="!searchFiltered()">
<recipe-card
v-bind:key="`mp_${m.id}`"
v-for="m in meal_plans"
:recipe="m.recipe"
:meal_plan="m"
:use_plural="use_plural"
:footer_text="m.meal_type_name"
footer_icon="far fa-calendar-alt"
></recipe-card>
</template>
style="display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); column-gap: 0.5rem;row-gap: 1rem; grid-auto-rows: max-content; ">
<!-- TODO remove once new meal plan view has proven to be good -->
<!-- <template v-if="!searchFiltered()">-->
<!-- <recipe-card-->
<!-- v-bind:key="`mp_${m.id}`"-->
<!-- v-for="m in meal_plans"-->
<!-- :recipe="m.recipe"-->
<!-- :meal_plan="m"-->
<!-- :use_plural="use_plural"-->
<!-- :footer_text="m.meal_type_name"-->
<!-- footer_icon="far fa-calendar-alt"-->
<!-- ></recipe-card>-->
<!-- </template>-->
<recipe-card v-for="r in recipes" v-bind:key="r.id" :recipe="r"
:footer_text="isRecentOrNew(r)[0]"
:footer_icon="isRecentOrNew(r)[1]"
:use_plural="use_plural">
</recipe-card>
</recipe-card>
</div>
</div>
</div>
<div class="row" style="margin-top: 2vh" v-if="!random_search">
<div class="col col-md-12">
<b-pagination pills v-model="search.pagination_page" :total-rows="pagination_count"
<b-pagination v-model="search.pagination_page" :total-rows="pagination_count" first-number
last-number size="lg"
:per-page="ui.page_size" @change="pageChange" align="center"></b-pagination>
</div>
</div>
@@ -894,6 +953,15 @@
</div>
</div>
</div>
<meal-plan-edit-modal
:entry="mealplan_entry_edit"
:create_date="mealplan_default_date"
></meal-plan-edit-modal>
<bottom-navigation-bar>
</bottom-navigation-bar>
</div>
</div>
</div>
@@ -916,7 +984,10 @@ import LoadingSpinner from "@/components/LoadingSpinner" // TODO: is this deprec
import RecipeCard from "@/components/RecipeCard"
import GenericMultiselect from "@/components/GenericMultiselect"
import RecipeSwitcher from "@/components/Buttons/RecipeSwitcher"
import { ApiApiFactory } from "@/utils/openapi/api"
import {ApiApiFactory} from "@/utils/openapi/api"
import {useMealPlanStore} from "@/stores/MealPlanStore";
import BottomNavigationBar from "@/components/BottomNavigationBar.vue";
import MealPlanEditModal from "@/components/MealPlanEditModal.vue";
Vue.use(VueCookies)
Vue.use(BootstrapVue)
@@ -927,7 +998,7 @@ let UI_COOKIE_NAME = "ui_search_settings"
export default {
name: "RecipeSearchView",
mixins: [ResolveUrlMixin, ApiMixin, ToastMixin],
components: {GenericMultiselect, RecipeCard, Treeselect, RecipeSwitcher, Multiselect},
components: {GenericMultiselect, RecipeCard, Treeselect, RecipeSwitcher, Multiselect, BottomNavigationBar, MealPlanEditModal},
data() {
return {
// this.Models and this.Actions inherited from ApiMixin
@@ -935,6 +1006,7 @@ export default {
recipes_loading: true,
facets: {Books: [], Foods: [], Keywords: []},
meal_plans: [],
meal_plan_store: null,
last_viewed_recipes: [],
sortMenu: false,
use_plural: false,
@@ -1015,9 +1087,27 @@ export default {
pagination_count: 0,
random_search: false,
debug: false,
mealplan_default_date: null,
mealplan_entry_edit: null,
image_placeholder: window.IMAGE_PLACEHOLDER,
}
},
computed: {
meal_plan_grid: function () {
let grid = []
if (this.meal_plan_store !== null && this.meal_plan_store.plan_list.length > 0) {
for (const x of Array(this.ui.meal_plan_days).keys()) {
let moment_date = moment().add(x, "d")
grid.push({
date: moment_date,
create_default_date: moment_date.format("YYYY-MM-DD"), // improve meal plan edit modal to do formatting itself and accept dates
date_label: moment_date.format('ddd DD.MM'),
plan_entries: this.meal_plan_store.plan_list.filter((m) => moment(m.date).isSame(moment_date, 'day'))
})
}
}
return grid
},
locale: function () {
return window.CUSTOM_LOCALE
},
@@ -1120,6 +1210,12 @@ export default {
})
return sort_order
},
isMobile: function () { //TODO move to central helper
return /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)
},
isTouch: function () {
return window.matchMedia("(pointer: coarse)").matches
}
},
mounted() {
@@ -1169,6 +1265,7 @@ export default {
this.use_plural = r.data.use_plural
})
this.$i18n.locale = window.CUSTOM_LOCALE
moment.locale(window.CUSTOM_LOCALE)
this.debug = localStorage.getItem("DEBUG") == "True" || false
},
watch: {
@@ -1257,21 +1354,26 @@ export default {
return [...new Map(data.map((item) => [key(item), item])).values()]
},
loadMealPlan: function () {
if (this.ui.show_meal_plan) {
let params = {
options: {
query: {
from_date: moment().format("YYYY-MM-DD"),
to_date: moment().add(this.ui.meal_plan_days, "days").format("YYYY-MM-DD"),
},
},
}
this.genericAPI(this.Models.MEAL_PLAN, this.Actions.LIST, params).then((result) => {
this.meal_plans = result.data
})
} else {
this.meal_plans = []
}
console.log('loadMealpLan')
this.meal_plan_store = useMealPlanStore()
this.meal_plan_store.refreshFromAPI(moment().format("YYYY-MM-DD"), moment().add(this.ui.meal_plan_days, "days").format("YYYY-MM-DD"))
// if (this.ui.show_meal_plan) {
// let params = {
// options: {
// query: {
// from_date: moment().format("YYYY-MM-DD"),
// to_date: moment().add(this.ui.meal_plan_days, "days").format("YYYY-MM-DD"),
// },
// },
// }
// this.genericAPI(this.Models.MEAL_PLAN, this.Actions.LIST, params).then((result) => {
// this.meal_plans = result.data
// })
// } else {
// this.meal_plans = []
// }
},
genericSelectChanged: function (obj) {
if (obj.var.includes("::")) {
@@ -1544,6 +1646,15 @@ export default {
type.filter((x) => x.operator === false && x.not === false).length > 1
)
},
showMealPlanEditModal: function (entry, date) {
this.mealplan_default_date = date
this.mealplan_entry_edit = entry
this.$nextTick(function () {
this.$bvModal.show(`id_meal_plan_edit_modal`)
})
}
},
}
</script>
@@ -1579,4 +1690,12 @@ export default {
width: 30px;
}
.hover-button {
display: none;
}
.hover-div:hover .hover-button {
display: inline-block;
}
</style>

View File

@@ -1,6 +1,7 @@
import Vue from 'vue'
import App from './RecipeSearchView'
import i18n from '@/i18n'
import {createPinia, PiniaVuePlugin} from "pinia";
Vue.config.productionTip = false
@@ -11,8 +12,11 @@ if (process.env.NODE_ENV === 'development') {
}
export default __webpack_public_path__ = publicPath // eslint-disable-line
Vue.use(PiniaVuePlugin)
const pinia = createPinia()
new Vue({
pinia,
i18n,
render: h => h(App),
}).$mount('#app')

View File

@@ -4,7 +4,7 @@
<loading-spinner></loading-spinner>
</template>
<div v-if="!loading">
<div v-if="!loading" style="padding-bottom: 60px">
<RecipeSwitcher ref="ref_recipe_switcher" @switch="quickSwitch($event)"/>
<div class="row">
<div class="col-12" style="text-align: center">
@@ -90,7 +90,6 @@
:ingredient_factor="ingredient_factor"
:servings="servings"
:header="true"
:use_plural="use_plural"
id="ingredient_container"
@checked-state-changed="updateIngredientCheckedState"
@change-servings="servings = $event"
@@ -124,7 +123,6 @@
:step="s"
:ingredient_factor="ingredient_factor"
:index="index"
:use_plural="use_plural"
:start_time="start_time"
@update-start-time="updateStartTime"
@checked-state-changed="updateIngredientCheckedState"
@@ -149,11 +147,14 @@
<add-recipe-to-book :recipe="recipe"></add-recipe-to-book>
<div class="row text-center d-print-none" style="margin-top: 3vh; margin-bottom: 3vh"
v-if="share_uid !== 'None'">
v-if="share_uid !== 'None' && !loading">
<div class="col col-md-12">
<a :href="resolveDjangoUrl('view_report_share_abuse', share_uid)">{{ $t("Report Abuse") }}</a>
<import-tandoor></import-tandoor> <br/>
<a :href="resolveDjangoUrl('view_report_share_abuse', share_uid)" class="mt-3">{{ $t("Report Abuse") }}</a>
</div>
</div>
<bottom-navigation-bar></bottom-navigation-bar>
</div>
</template>
@@ -182,6 +183,8 @@ import NutritionComponent from "@/components/NutritionComponent"
import RecipeSwitcher from "@/components/Buttons/RecipeSwitcher"
import CustomInputSpinButton from "@/components/CustomInputSpinButton"
import {ApiApiFactory} from "@/utils/openapi/api";
import ImportTandoor from "@/components/Modals/ImportTandoor.vue";
import BottomNavigationBar from "@/components/BottomNavigationBar.vue";
Vue.prototype.moment = moment
@@ -191,6 +194,7 @@ export default {
name: "RecipeView",
mixins: [ResolveUrlMixin, ToastMixin],
components: {
ImportTandoor,
LastCooked,
RecipeRating,
PdfViewer,
@@ -204,6 +208,7 @@ export default {
AddRecipeToBook,
RecipeSwitcher,
CustomInputSpinButton,
BottomNavigationBar,
},
computed: {
ingredient_factor: function () {
@@ -221,7 +226,6 @@ export default {
},
data() {
return {
use_plural: false,
loading: true,
recipe: undefined,
rootrecipe: undefined,
@@ -244,10 +248,6 @@ export default {
this.requestWakeLock()
window.addEventListener('resize', this.handleResize);
let apiClient = new ApiApiFactory()
apiClient.retrieveSpace(window.ACTIVE_SPACE_ID).then(r => {
this.use_plural = r.data.use_plural
})
},
beforeUnmount() {
this.destroyWakeLock()

View File

@@ -1,6 +1,7 @@
import Vue from 'vue'
import App from './RecipeView.vue'
import i18n from "@/i18n";
import {createPinia, PiniaVuePlugin} from 'pinia'
Vue.config.productionTip = false
@@ -11,8 +12,11 @@ if (process.env.NODE_ENV === 'development') {
}
export default __webpack_public_path__ = publicPath // eslint-disable-line
Vue.use(PiniaVuePlugin)
const pinia = createPinia()
new Vue({
pinia,
i18n,
render: h => h(App),
}).$mount('#app')

View File

@@ -1,6 +1,7 @@
import Vue from 'vue'
import App from './SettingsView.vue'
import i18n from '@/i18n'
import {createPinia, PiniaVuePlugin} from "pinia";
Vue.config.productionTip = false
@@ -11,7 +12,11 @@ if (process.env.NODE_ENV === 'development') {
}
export default __webpack_public_path__ = publicPath // eslint-disable-line
Vue.use(PiniaVuePlugin)
const pinia = createPinia()
new Vue({
pinia,
i18n,
render: h => h(App),
}).$mount('#app')

View File

@@ -1,6 +1,7 @@
<template>
<div id="app" style="margin-bottom: 4vh">
<div id="app">
<b-alert :show="!online" dismissible class="small float-up" variant="warning">{{ $t("OfflineAlert") }}</b-alert>
<div class="row float-top w-100">
<div class="col-auto no-gutter ml-auto">
<b-button variant="link" class="px-1 pt-0 pb-1 d-none d-md-inline-block">
@@ -469,30 +470,6 @@
</b-tab>
</b-tabs>
<transition name="slided-fade">
<div class="row fixed-bottom p-2 b-1 border-top text-center d-flex d-md-none"
style="background: rgba(255, 255, 255, 0.6);width: 105%;" v-if="current_tab === 0">
<div class="col-6">
<a class="btn btn-block btn-success shadow-none" @click="entrymode = !entrymode; "
><i class="fas fa-cart-plus"></i>
{{ $t("New_Entry") }}
</a>
</div>
<div class="col-6">
<b-dropdown id="dropdown-dropup" block dropup variant="primary" class="shadow-none">
<template #button-content><i class="fas fa-download"></i> {{ $t("Export") }}</template>
<DownloadPDF dom="#shoppinglist" name="shopping.pdf" :label="$t('download_pdf')"
icon="far fa-file-pdf"/>
<DownloadCSV :items="csvData" :delim="settings.csv_delim" name="shopping.csv"
:label="$t('download_csv')" icon="fas fa-file-csv"/>
<CopyToClipboard :items="csvData" :settings="settings" :label="$t('copy_to_clipboard')"
icon="fas fa-clipboard-list"/>
<CopyToClipboard :items="csvData" :settings="settings" format="table"
:label="$t('copy_markdown_table')" icon="fab fa-markdown"/>
</b-dropdown>
</div>
</div>
</transition>
<b-popover target="id_filters_button" triggers="click" placement="bottomleft" :title="$t('Filters')">
<div>
<b-form-group v-bind:label="$t('GroupBy')" label-for="popover-input-1" label-cols="6" class="mb-1">
@@ -588,6 +565,29 @@
</ContextMenu>
<shopping-modal v-if="new_recipe.id" :recipe="new_recipe" :servings="parseInt(add_recipe_servings)"
:modal_id="new_recipe.id" @finish="finishShopping" :list_recipe="new_recipe.list_recipe"/>
<bottom-navigation-bar>
<template #custom_create_functions>
<div class="dropdown-divider"></div>
<h6 class="dropdown-header">{{ $t('Shopping_list')}}</h6>
<a class="dropdown-item" @click="entrymode = !entrymode; " ><i class="fas fa-cart-plus"></i>
{{ $t("New_Entry") }}
</a>
<DownloadPDF dom="#shoppinglist" name="shopping.pdf" :label="$t('download_pdf')"
icon="far fa-file-pdf fa-fw"/>
<DownloadCSV :items="csvData" :delim="settings.csv_delim" name="shopping.csv"
:label="$t('download_csv')" icon="fas fa-file-csv fa-fw"/>
<CopyToClipboard :items="csvData" :settings="settings" :label="$t('copy_to_clipboard')"
icon="fas fa-clipboard-list fa-fw"/>
<CopyToClipboard :items="csvData" :settings="settings" format="table"
:label="$t('copy_markdown_table')" icon="fab fa-markdown fa-fw"/>
</template>
</bottom-navigation-bar>
</div>
</template>
@@ -615,6 +615,8 @@ import ShoppingSettingsComponent from "@/components/Settings/ShoppingSettingsCom
Vue.use(BootstrapVue)
Vue.use(VueCookies)
let SETTINGS_COOKIE_NAME = "shopping_settings"
import {Workbox} from 'workbox-window';
import BottomNavigationBar from "@/components/BottomNavigationBar.vue";
export default {
name: "ShoppingListView",
@@ -630,7 +632,8 @@ export default {
CopyToClipboard,
ShoppingModal,
draggable,
ShoppingSettingsComponent
ShoppingSettingsComponent,
BottomNavigationBar,
},
data() {
@@ -903,9 +906,30 @@ export default {
}
})
this.$i18n.locale = window.CUSTOM_LOCALE
console.log(window.CUSTOM_LOCALE)
},
methods: {
/**
* failed requests to sync entry check events are automatically re-queued by the service worker for sync
* this command allows to manually force replaying those events before re-enabling automatic sync
*/
replaySyncQueue: function () {
const wb = new Workbox('/service-worker.js');
wb.register();
wb.messageSW({type: 'BGSYNC_REPLAY_REQUESTS'}).then((r) => {
console.log('Background sync queue replayed!', r);
})
},
/**
* get the number of entries left in the sync queue for entry check events
* @returns {Promise<Number>} promise resolving to the number of entries left
*/
getSyncQueueLength: function () {
const wb = new Workbox('/service-worker.js');
wb.register();
return wb.messageSW({type: 'BGSYNC_COUNT_QUEUE'}).then((r) => {
return r
})
},
setFocus() {
if (this.ui.entry_mode_simple) {
this.$refs['amount_input_simple'].focus()
@@ -1043,21 +1067,27 @@ export default {
} else {
this.loading = true
}
this.genericAPI(this.Models.SHOPPING_LIST, this.Actions.LIST, params)
.then((results) => {
if (!autosync) {
if (results.data?.length) {
this.items = results.data
} else {
console.log("no data returned")
}
this.loading = false
this.genericAPI(this.Models.SHOPPING_LIST, this.Actions.LIST, params).then((results) => {
if (!autosync) {
if (results.data?.length) {
this.items = results.data
} else {
if (!this.auto_sync_blocked) {
this.mergeShoppingList(results.data)
}
console.log("no data returned")
}
})
this.loading = false
} else {
if (!this.auto_sync_blocked) {
this.getSyncQueueLength().then((r) => {
if (r === 0) {
this.mergeShoppingList(results.data)
} else {
this.auto_sync_running = false
this.replaySyncQueue()
}
})
}
}
})
.catch((err) => {
if (!autosync) {
StandardToasts.makeStandardToast(this, StandardToasts.FAIL_FETCH, err)

View File

@@ -1,6 +1,7 @@
import i18n from "@/i18n"
import Vue from "vue"
import App from "./ShoppingListView"
import {createPinia, PiniaVuePlugin} from "pinia";
Vue.config.productionTip = false
@@ -11,7 +12,11 @@ if (process.env.NODE_ENV === "development") {
}
export default __webpack_public_path__ = publicPath // eslint-disable-line
Vue.use(PiniaVuePlugin)
const pinia = createPinia()
new Vue({
pinia,
i18n,
render: (h) => h(App),
}).$mount("#app")

View File

@@ -151,9 +151,6 @@
<b-form-checkbox v-model="space.show_facet_count"> Facet Count</b-form-checkbox>
<span class="text-muted small">{{ $t('facet_count_info') }}</span><br/>
<b-form-checkbox v-model="space.use_plural">Use Plural form</b-form-checkbox>
<span class="text-muted small">{{ $t('plural_usage_info') }}</span><br/>
<label>{{ $t('FoodInherit') }}</label>
<generic-multiselect :initial_selection="space.food_inherit"
:model="Models.FOOD_INHERIT_FIELDS"

View File

@@ -1,6 +1,7 @@
import Vue from 'vue'
import App from './SpaceManageView.vue'
import i18n from '@/i18n'
import {createPinia, PiniaVuePlugin} from "pinia";
Vue.config.productionTip = false
@@ -11,8 +12,11 @@ if (process.env.NODE_ENV === 'development') {
}
export default __webpack_public_path__ = publicPath // eslint-disable-line
Vue.use(PiniaVuePlugin)
const pinia = createPinia()
new Vue({
pinia,
i18n,
render: h => h(App),
}).$mount('#app')

View File

@@ -1,6 +1,7 @@
import Vue from 'vue'
import App from './SupermarketView.vue'
import i18n from '@/i18n'
import {createPinia, PiniaVuePlugin} from "pinia";
Vue.config.productionTip = false
@@ -11,8 +12,11 @@ if (process.env.NODE_ENV === 'development') {
}
export default __webpack_public_path__ = publicPath // eslint-disable-line
Vue.use(PiniaVuePlugin)
const pinia = createPinia()
new Vue({
pinia,
i18n,
render: h => h(App),
}).$mount('#app')

View File

@@ -1,39 +1,155 @@
<template>
<div id="app">
<div class="row" v-if="food">
<div class="col-12">
<h2>{{ food.name }}</h2>
</div>
</div>
<div class="row">
<div class="col-12">
<b-form v-if="food">
<b-form-group :label="$t('Name')" description="">
<b-form-input v-model="food.name"></b-form-input>
</b-form-group>
<b-form-group :label="$t('Plural')" description="">
<b-form-input v-model="food.plural_name"></b-form-input>
</b-form-group>
<b-form-group :label="$t('Recipe')" :description="$t('food_recipe_help')">
<generic-multiselect
@change="food.recipe = $event.val;"
:model="Models.RECIPE"
:initial_selection="food.recipe"
label="name"
:multiple="false"
:placeholder="$t('Recipe')"
></generic-multiselect>
</b-form-group>
<b-form-group :description="$t('OnHand_help')">
<b-form-checkbox v-model="food.food_onhand">{{ $t('OnHand') }}</b-form-checkbox>
</b-form-group>
<b-form-group :description="$t('ignore_shopping_help')">
<b-form-checkbox v-model="food.ignore_shopping">{{ $t('Ignore_Shopping') }}</b-form-checkbox>
</b-form-group>
<b-form-group :label="$t('Shopping_Category')" :description="$t('shopping_category_help')">
<generic-multiselect
@change="food.supermarket_category = $event.val;"
:model="Models.SHOPPING_CATEGORY"
:initial_selection="food.supermarket_category"
label="name"
:multiple="false"
:placeholder="$t('Shopping_Category')"
></generic-multiselect>
</b-form-group>
<hr/>
<!-- todo add conditions if false disable dont hide -->
<b-form-group :label="$t('Substitutes')" :description="$t('substitute_help')">
<generic-multiselect
@change="food.substitute = $event.val;"
:model="Models.FOOD"
:initial_selection="food.substitute"
label="name"
:multiple="false"
:placeholder="$t('Substitutes')"
></generic-multiselect>
</b-form-group>
<b-form-group :description="$t('substitute_siblings_help')">
<b-form-checkbox v-model="food.substitute_siblings">{{ $t('substitute_siblings') }}</b-form-checkbox>
</b-form-group>
<b-form-group :label="$t('InheritFields')" :description="$t('InheritFields_help')">
<generic-multiselect
@change="food.inherit_fields = $event.val;"
:model="Models.FOOD_INHERIT_FIELDS"
:initial_selection="food.inherit_fields"
label="name"
:multiple="false"
:placeholder="$t('InheritFields')"
></generic-multiselect>
</b-form-group>
<b-form-group :label="$t('ChildInheritFields')" :description="$t('ChildInheritFields_help')">
<generic-multiselect
@change="food.child_inherit_fields = $event.val;"
:model="Models.FOOD_INHERIT_FIELDS"
:initial_selection="food.child_inherit_fields"
label="name"
:multiple="false"
:placeholder="$t('ChildInheritFields')"
></generic-multiselect>
</b-form-group>
<!-- TODO change to a button -->
<b-form-group :description="$t('reset_children_help')">
<b-form-checkbox v-model="food.reset_inherit">{{ $t('reset_children') }}</b-form-checkbox>
</b-form-group>
<b-button variant="primary" @click="updateFood">{{ $t('Save') }}</b-button>
</b-form>
</div>
</div>
</div>
</template>
<script>
import Vue from "vue"
import { BootstrapVue } from "bootstrap-vue"
import {BootstrapVue} from "bootstrap-vue"
import "bootstrap-vue/dist/bootstrap-vue.css"
import {ApiApiFactory} from "@/utils/openapi/api";
import RecipeCard from "@/components/RecipeCard.vue";
import GenericMultiselect from "@/components/GenericMultiselect.vue";
import {ApiMixin, StandardToasts} from "@/utils/utils";
Vue.use(BootstrapVue)
//import Multiselect from "vue-multiselect"
export default {
name: "TestView",
mixins: [],
mixins: [ApiMixin],
components: {
// Multiselect,
GenericMultiselect
},
data() {
return {
food: undefined,
}
},
mounted() {
this.$i18n.locale = window.CUSTOM_LOCALE
let apiClient = new ApiApiFactory()
apiClient.retrieveFood('1').then((r) => {
this.food = r.data
})
},
methods: {
updateFood: function () {
let apiClient = new ApiApiFactory()
apiClient.updateFood(this.food.id, this.food).then((r) => {
this.food = r.data
StandardToasts.makeStandardToast(this, StandardToasts.SUCCESS_UPDATE)
}).catch(err => {
StandardToasts.makeStandardToast(this, StandardToasts.FAIL_UPDATE, err)
})
}
},
}
</script>
<style></style>
<style>
</style>

View File

@@ -1,6 +1,7 @@
import Vue from 'vue'
import App from './TestView.vue'
import i18n from '@/i18n'
import {createPinia, PiniaVuePlugin} from "pinia";
Vue.config.productionTip = false
@@ -11,8 +12,11 @@ if (process.env.NODE_ENV === 'development') {
}
export default __webpack_public_path__ = publicPath // eslint-disable-line
Vue.use(PiniaVuePlugin)
const pinia = createPinia()
new Vue({
pinia,
i18n,
render: h => h(App),
}).$mount('#app')

0
vue/src/apps/base_app.js Normal file
View File

View File

@@ -0,0 +1,100 @@
<template>
<!-- bottom button nav -->
<div class="fixed-bottom p-1 pt-2 pl-2 pr-2 border-top text-center d-lg-none" style="background: white">
<div class="d-flex flex-row justify-content-around">
<div class="flex-column" v-if="show_button_1">
<slot name="button_1">
<a class="nav-link bottom-nav-link p-0" v-bind:href="resolveDjangoUrl('view_search')">
<i class="fas fa-fw fa-book " style="font-size: 1.5em"></i><br/><small>{{ $t('Recipes') }}</small></a> <!-- TODO localize -->
</slot>
</div>
<div class="flex-column" v-if="show_button_2">
<slot name="button_2">
<a class="nav-link bottom-nav-link p-0" v-bind:href="resolveDjangoUrl('view_plan')">
<i class="fas fa-calendar-alt" style="font-size: 1.5em"></i><br/><small>{{ $t('Meal_Plan') }}</small></a>
</slot>
</div>
<div class="flex-column" v-if="show_button_create">
<slot name="button_create">
<div class="dropup">
<a class="nav-link bottom-nav-link p-0" href="#" id="navbarDropdownMenuLink" data-toggle="dropdown"
aria-haspopup="true" aria-expanded="false"><i class="fas fa-plus-circle fa-2x bottom-nav-link"></i>
</a>
<div class="dropdown-menu center-dropup" aria-labelledby="navbarDropdownMenuLink">
<a class="dropdown-item" v-bind:href="resolveDjangoUrl('new_recipe')"><i
class="fas fa-fw fa-plus"></i> {{ $t('Create Recipe') }}</a>
<a class="dropdown-item" v-bind:href="resolveDjangoUrl('data_import_url')"><i
class="fas fa-fw fa-file-import"></i> {{ $t('Import Recipe') }}</a>
<div class="dropdown-divider" v-if="create_links.length > 0"></div>
<slot name="custom_create_functions">
</slot>
<a class="dropdown-item" v-bind:href="cl.url" v-for="cl in create_links" v-bind:key="cl.label">
<i :class="cl.icon + ' fa-fw'"></i> {{ cl.label }}
</a>
</div>
</div>
</slot>
</div>
<div class="flex-column" v-if="show_button_3">
<slot name="button_3">
<a class="nav-link bottom-nav-link p-0" v-bind:href="resolveDjangoUrl('view_shopping')">
<i class="fas fa-shopping-cart" style="font-size: 1.5em"></i><br/><small>{{ $t('Shopping_list') }}</small></a>
</slot>
</div>
<div class="flex-column">
<slot name="button_4" v-if="show_button_4">
<a class="nav-link bottom-nav-link p-0" v-bind:href="resolveDjangoUrl('view_books')">
<i class="fas fa-book-open" style="font-size: 1.5em"></i><br/><small>{{ $t('Books') }}</small></a> <!-- TODO localize -->
</slot>
</div>
</div>
</div>
</template>
<script>
import {ResolveUrlMixin} from "@/utils/utils";
export default {
name: "BottomNavigationBar",
mixins: [ResolveUrlMixin],
props: {
create_links: {
type: Array, default() {
return []
}
},
show_button_1: {type: Boolean, default: true},
show_button_2: {type: Boolean, default: true},
show_button_3: {type: Boolean, default: true},
show_button_4: {type: Boolean, default: true},
show_button_create: {type: Boolean, default: true},
}
}
</script>
<style scoped>
.bottom-nav-link {
color: #666666
}
.center-dropup {
right: auto;
left: 50%;
-webkit-transform: translate(-50%, 0);
-o-transform: translate(-50%, 0);
transform: translate(-50%, 0);
}
</style>

View File

@@ -95,7 +95,7 @@ export default {
<style scoped>
.context-menu {
position: fixed;
z-index: 999;
z-index: 5000;
overflow: hidden;
background: #fff;
border-radius: 4px;

View File

@@ -12,7 +12,7 @@
<cookbook-edit-card :book="book" v-if="current_page === 1" v-on:editing="cookbook_editing = $event" v-on:refresh="$emit('refresh')" @reload="$emit('reload')"></cookbook-edit-card>
</transition>
<transition name="flip" mode="out-in">
<recipe-card :recipe="display_recipes[0].recipe_content" v-if="current_page > 1" :key="display_recipes[0].recipe" :use_plural="use_plural"></recipe-card>
<recipe-card :recipe="display_recipes[0].recipe_content" v-if="current_page > 1" :key="display_recipes[0].recipe" ></recipe-card>
</transition>
</div>
<div class="col-md-5">

View File

@@ -23,9 +23,9 @@
<b-card-body class="m-0 py-0">
<b-card-text class="h-100 my-0 d-flex flex-column" style="text-overflow: ellipsis">
<h5 class="m-0 mt-1 text-truncate">{{ item[title] }}</h5>
<template v-if="use_plural">
<div v-if="item[plural] !== '' && item[plural] !== null" class="m-0 text-truncate">({{ $t("plural_short") }}: {{ item[plural] }})</div>
</template>
<div v-if="item[plural]!== '' && item[plural] !== null && item[plural] !== undefined" class="m-0 text-truncate">({{ $t("plural_short") }}: {{ item[plural] }})</div>
<div class="m-0 text-truncate">{{ item[subtitle] }}</div>
<div class="m-0 text-truncate small text-muted" v-if="getFullname">{{ getFullname }}</div>

View File

@@ -155,8 +155,9 @@ export default {
pageSize: this.limit,
query: query,
limit: this.limit,
options: {query: {simple: 1}}, // for API endpoints that support a simple view
}
console.log(query, options)
this.genericAPI(this.model, this.Actions.LIST, options).then((result) => {
this.objects = this.sticky_options.concat(result.data?.results ?? result.data)
if (this.nothingSelected && this.objects.length > 0) {

View File

@@ -17,10 +17,7 @@
</td>
<td @click="done">
<template v-if="ingredient.unit !== null && !ingredient.no_amount">
<template v-if="!use_plural">
<span>{{ ingredient.unit.name }}</span>
</template>
<template v-else>
<template >
<template v-if="ingredient.unit.plural_name === '' || ingredient.unit.plural_name === null">
<span>{{ ingredient.unit.name }}</span>
</template>
@@ -38,10 +35,8 @@
v-if="ingredient.food.recipe !== null" target="_blank"
rel="noopener noreferrer">{{ ingredient.food.name }}</a>
<template v-if="ingredient.food.recipe === null">
<template v-if="!use_plural">
<span>{{ ingredient.food.name }}</span>
</template>
<template v-else>
<template>
<template v-if="ingredient.food.plural_name === '' || ingredient.food.plural_name === null">
<span>{{ ingredient.food.name }}</span>
</template>
@@ -84,7 +79,6 @@ export default {
props: {
ingredient: Object,
ingredient_factor: {type: Number, default: 1},
use_plural:{type: Boolean, default: false},
detailed: {type: Boolean, default: true},
},
mixins: [ResolveUrlMixin],

View File

@@ -1,6 +1,6 @@
<template>
<div v-if="recipe.keywords.length > 0">
<span :key="k.id" v-for="k in recipe.keywords.filter((kk) => { return kk.show || kk.show === undefined })" class="pl-1">
<span :key="k.id" v-for="k in recipe.keywords.slice(0,keyword_splice).filter((kk) => { return kk.show || kk.show === undefined })" class="pl-1">
<a :href="`${resolveDjangoUrl('view_search')}?keyword=${k.id}`"><b-badge pill variant="light"
class="font-weight-normal">{{ k.label }}</b-badge></a>
@@ -17,6 +17,15 @@ export default {
mixins: [ResolveUrlMixin],
props: {
recipe: Object,
limit: Number,
},
computed: {
keyword_splice: function (){
if(this.limit){
return this.limit
}
return this.recipe.keywords.lenght
}
}
}
</script>

View File

@@ -1,114 +1,148 @@
<template>
<b-modal :id="modal_id" size="lg" :title="modal_title" hide-footer aria-label="" @show="showModal">
<div class="row">
<div class="col col-md-12">
<div class="row">
<div class="col col-md-12">
<div class="row">
<div class="col-6 col-lg-9">
<b-input-group>
<b-form-input id="TitleInput" v-model="entryEditing.title" :placeholder="entryEditing.title_placeholder" @change="missing_recipe = false"></b-form-input>
<b-input-group-append class="d-none d-lg-block">
<b-button variant="primary" @click="entryEditing.title = ''"><i class="fa fa-eraser"></i></b-button>
</b-input-group-append>
</b-input-group>
<span class="text-danger" v-if="missing_recipe">{{ $t("Title_or_Recipe_Required") }}</span>
<small tabindex="-1" class="form-text text-muted" v-if="!missing_recipe">{{ $t("Title") }}</small>
<div>
<b-modal :id="modal_id" size="lg" :title="modal_title" hide-footer aria-label="" @show="showModal">
<div class="row" v-if="entryEditing !== null">
<div class="col col-md-12">
<div class="row">
<div class="col col-md-12">
<div class="row">
<div class="col-6 col-lg-9">
<b-input-group>
<b-form-input id="TitleInput" v-model="entryEditing.title"
:placeholder="entryEditing.title_placeholder"
@change="missing_recipe = false"></b-form-input>
<b-input-group-append class="d-none d-lg-block">
<b-button variant="primary" @click="entryEditing.title = ''"><i
class="fa fa-eraser"></i></b-button>
</b-input-group-append>
</b-input-group>
<span class="text-danger" v-if="missing_recipe">{{
$t("Title_or_Recipe_Required")
}}</span>
<small tabindex="-1" class="form-text text-muted" v-if="!missing_recipe">{{
$t("Title")
}}</small>
</div>
<div class="col-6 col-lg-3">
<input type="date" id="DateInput" class="form-control" v-model="entryEditing.date"/>
<small tabindex="-1" class="form-text text-muted">{{ $t("Date") }}</small>
</div>
</div>
<div class="col-6 col-lg-3">
<input type="date" id="DateInput" class="form-control" v-model="entryEditing.date" />
<small tabindex="-1" class="form-text text-muted">{{ $t("Date") }}</small>
<div class="row mt-3">
<div class="col-12 col-lg-6 col-xl-6">
<b-form-group>
<generic-multiselect
@change="selectRecipe"
:initial_single_selection="entryEditing.recipe"
:label="'name'"
:model="Models.RECIPE"
style="flex-grow: 1; flex-shrink: 1; flex-basis: 0"
v-bind:placeholder="$t('Recipe')"
:limit="10"
:multiple="false"
></generic-multiselect>
<small tabindex="-1" class="form-text text-muted">{{ $t("Recipe") }}</small>
</b-form-group>
<b-form-group class="mt-3">
<generic-multiselect
required
@change="selectMealType"
:label="'name'"
:model="Models.MEAL_TYPE"
style="flex-grow: 1; flex-shrink: 1; flex-basis: 0"
v-bind:placeholder="$t('Meal_Type')"
:limit="10"
:multiple="false"
:initial_single_selection="entryEditing.meal_type"
:allow_create="true"
:create_placeholder="$t('Create_New_Meal_Type')"
></generic-multiselect>
<span class="text-danger" v-if="missing_meal_type">{{
$t("Meal_Type_Required")
}}</span>
<small tabindex="-1" class="form-text text-muted"
v-if="!missing_meal_type">{{ $t("Meal_Type") }}</small>
</b-form-group>
<b-form-group label-for="NoteInput" :description="$t('Note')" class="mt-3">
<textarea class="form-control" id="NoteInput" v-model="entryEditing.note"
:placeholder="$t('Note')"></textarea>
</b-form-group>
<b-input-group>
<b-form-input id="ServingsInput" v-model="entryEditing.servings"
:placeholder="$t('Servings')"></b-form-input>
</b-input-group>
<small tabindex="-1" class="form-text text-muted">{{ $t("Servings") }}</small>
<b-form-group class="mt-3">
<generic-multiselect
required
@change="entryEditing.shared = $event.val"
parent_variable="entryEditing.shared"
:label="'display_name'"
:model="Models.USER_NAME"
style="flex-grow: 1; flex-shrink: 1; flex-basis: 0"
v-bind:placeholder="$t('Share')"
:limit="10"
:multiple="true"
:initial_selection="entryEditing.shared"
></generic-multiselect>
<small tabindex="-1" class="form-text text-muted">{{ $t("Share") }}</small>
</b-form-group>
<b-input-group v-if="!autoMealPlan">
<b-form-checkbox id="AddToShopping" v-model="mealplan_settings.addshopping"/>
<small tabindex="-1" class="form-text text-muted">{{
$t("AddToShopping")
}}</small>
</b-input-group>
<b-input-group v-if="mealplan_settings.addshopping && !autoMealPlan">
<b-form-checkbox id="reviewShopping"
v-model="mealplan_settings.reviewshopping"/>
<small tabindex="-1" class="form-text text-muted">{{
$t("review_shopping")
}}</small>
</b-input-group>
</div>
<div class="col-lg-6 d-none d-lg-block d-xl-block">
<recipe-card v-if="entryEditing.recipe" :recipe="entryEditing.recipe"
:detailed="false"></recipe-card>
</div>
</div>
</div>
<div class="row mt-3">
<div class="col-12 col-lg-6 col-xl-6">
<b-form-group>
<generic-multiselect
@change="selectRecipe"
:initial_single_selection="entryEditing.recipe"
:label="'name'"
:model="Models.RECIPE"
style="flex-grow: 1; flex-shrink: 1; flex-basis: 0"
v-bind:placeholder="$t('Recipe')"
:limit="10"
:multiple="false"
></generic-multiselect>
<small tabindex="-1" class="form-text text-muted">{{ $t("Recipe") }}</small>
</b-form-group>
<b-form-group class="mt-3">
<generic-multiselect
required
@change="selectMealType"
:label="'name'"
:model="Models.MEAL_TYPE"
style="flex-grow: 1; flex-shrink: 1; flex-basis: 0"
v-bind:placeholder="$t('Meal_Type')"
:limit="10"
:multiple="false"
:initial_single_selection="entryEditing.meal_type"
:allow_create="true"
:create_placeholder="$t('Create_New_Meal_Type')"
></generic-multiselect>
<span class="text-danger" v-if="missing_meal_type">{{ $t("Meal_Type_Required") }}</span>
<small tabindex="-1" class="form-text text-muted" v-if="!missing_meal_type">{{ $t("Meal_Type") }}</small>
</b-form-group>
<b-form-group label-for="NoteInput" :description="$t('Note')" class="mt-3">
<textarea class="form-control" id="NoteInput" v-model="entryEditing.note" :placeholder="$t('Note')"></textarea>
</b-form-group>
<b-input-group>
<b-form-input id="ServingsInput" v-model="entryEditing.servings" :placeholder="$t('Servings')"></b-form-input>
</b-input-group>
<small tabindex="-1" class="form-text text-muted">{{ $t("Servings") }}</small>
<b-form-group class="mt-3">
<generic-multiselect
required
@change="entryEditing.shared = $event.val"
parent_variable="entryEditing.shared"
:label="'display_name'"
:model="Models.USER_NAME"
style="flex-grow: 1; flex-shrink: 1; flex-basis: 0"
v-bind:placeholder="$t('Share')"
:limit="10"
:multiple="true"
:initial_selection="entryEditing.shared"
></generic-multiselect>
<small tabindex="-1" class="form-text text-muted">{{ $t("Share") }}</small>
</b-form-group>
<b-input-group v-if="!autoMealPlan">
<b-form-checkbox id="AddToShopping" v-model="mealplan_settings.addshopping" />
<small tabindex="-1" class="form-text text-muted">{{ $t("AddToShopping") }}</small>
</b-input-group>
<b-input-group v-if="mealplan_settings.addshopping">
<b-form-checkbox id="reviewShopping" v-model="mealplan_settings.reviewshopping" />
<small tabindex="-1" class="form-text text-muted">{{ $t("review_shopping") }}</small>
</b-input-group>
</div>
<div class="col-lg-6 d-none d-lg-block d-xl-block">
<recipe-card v-if="entryEditing.recipe" :recipe="entryEditing.recipe" :detailed="false" :use_plural="use_plural"></recipe-card>
</div>
</div>
<div class="row mt-3 mb-3">
<div class="col-12">
<b-button variant="danger" @click="deleteEntry" v-if="allow_delete">{{ $t("Delete") }} </b-button>
<b-button class="float-right" variant="primary" @click="editEntry">{{ $t("Save") }}</b-button>
<div class="row mt-3 mb-3">
<div class="col-12">
<b-button variant="danger" @click="deleteEntry" v-if="allow_delete">{{
$t("Delete")
}}
</b-button>
<b-button class="float-right" variant="primary" @click="editEntry">{{
$t("Save")
}}
</b-button>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</b-modal>
</b-modal>
<shopping-modal :recipe="last_created_plan.recipe" :servings="last_created_plan.servings" :modal_id="999999"
:mealplan="last_created_plan" v-if="last_created_plan !== null && last_created_plan.recipe !== null"/>
</div>
</template>
<script>
import Vue from "vue"
import VueCookies from "vue-cookies"
import { BootstrapVue } from "bootstrap-vue"
import {BootstrapVue} from "bootstrap-vue"
import GenericMultiselect from "@/components/GenericMultiselect"
import { ApiMixin, getUserPreference } from "@/utils/utils"
import {ApiMixin, getUserPreference} from "@/utils/utils"
const { ApiApiFactory } = require("@/utils/openapi/api")
const { StandardToasts } = require("@/utils/utils")
const {ApiApiFactory} = require("@/utils/openapi/api")
const {StandardToasts} = require("@/utils/utils")
import {useUserPreferenceStore} from "@/stores/UserPreferenceStore";
import {useMealPlanStore} from "@/stores/MealPlanStore";
import ShoppingModal from "@/components/Modals/ShoppingModal.vue";
Vue.use(BootstrapVue)
Vue.use(VueCookies)
@@ -118,11 +152,11 @@ export default {
name: "MealPlanEditModal",
props: {
entry: Object,
entryEditing_inital_servings: Number,
create_date: String,
modal_title: String,
modal_id: {
type: String,
default: "edit-modal",
default: "id_meal_plan_edit_modal",
},
allow_delete: {
type: Boolean,
@@ -133,10 +167,11 @@ export default {
components: {
GenericMultiselect,
RecipeCard: () => import("@/components/RecipeCard.vue"),
ShoppingModal,
},
data() {
return {
entryEditing: {},
entryEditing: null,
missing_recipe: false,
missing_meal_type: false,
default_plan_share: [],
@@ -144,22 +179,19 @@ export default {
addshopping: false,
reviewshopping: false,
},
use_plural: false,
last_created_plan: null,
}
},
watch: {
entry: {
handler() {
this.entryEditing = Object.assign({}, this.entry)
if (this.entryEditing_inital_servings) {
this.entryEditing.servings = this.entryEditing_inital_servings
}
},
deep: true,
},
entryEditing: {
handler(newVal) {},
handler(newVal) {
},
deep: true,
},
mealplan_settings: {
@@ -168,19 +200,13 @@ export default {
},
deep: true,
},
entryEditing_inital_servings: function (newVal) {
this.entryEditing.servings = newVal
},
},
mounted: function () {
let apiClient = new ApiApiFactory()
apiClient.retrieveSpace(window.ACTIVE_SPACE_ID).then(r => {
this.use_plural = r.data.use_plural
})
useUserPreferenceStore().updateIfStaleOrEmpty()
},
computed: {
autoMealPlan: function () {
return getUserPreference("mealplan_autoadd_shopping")
return useUserPreferenceStore().getStaleData()?.mealplan_autoadd_shopping
},
},
methods: {
@@ -188,35 +214,53 @@ export default {
if (this.$cookies.isKey(MEALPLAN_COOKIE_NAME)) {
this.mealplan_settings = Object.assign({}, this.mealplan_settings, this.$cookies.get(MEALPLAN_COOKIE_NAME))
}
let apiClient = new ApiApiFactory()
apiClient.listUserPreferences().then((result) => {
if (this.entry.id === -1) {
this.entryEditing.shared = result.data[0].plan_share
if (this.entry === null) {
this.entryEditing = Object.assign({}, useMealPlanStore().empty_meal_plan, null)
} else {
this.entryEditing = Object.assign({}, this.entry, null)
}
if (this.create_date) {
this.entryEditing.date = this.create_date
}
useUserPreferenceStore().getData().then(userPreference => {
if (this.entryEditing.id === -1) {
this.entryEditing.shared = userPreference.plan_share
}
})
},
editEntry() {
this.missing_meal_type = false
this.missing_recipe = false
let cancel = false
if (this.entryEditing.meal_type == null) {
this.missing_meal_type = true
cancel = true
return;
}
if (this.entryEditing.recipe == null && this.entryEditing.title === "") {
this.missing_recipe = true
cancel = true
return
}
if (!cancel) {
this.$bvModal.hide(`edit-modal`)
this.$emit("save-entry", { ...this.mealplan_settings, ...this.entryEditing, ...{ addshopping: this.mealplan_settings.addshopping && !this.autoMealPlan } })
//TODO properly validate
this.$bvModal.hide(this.modal_id)
// only set addshopping if review is not enabled
this.$set(this.entryEditing, 'addshopping', (this.mealplan_settings.addshopping && !this.mealplan_settings.reviewshopping))
if (!('id' in this.entryEditing) || this.entryEditing.id === -1) {
useMealPlanStore().createObject(this.entryEditing).then((r) => {
this.last_created_plan = r.data
if (r.data.recipe && this.mealplan_settings.addshopping && !this.autoMealPlan && this.mealplan_settings.reviewshopping) {
this.$nextTick(function () {
this.$bvModal.show(`shopping_999999`)
})
}
})
} else {
useMealPlanStore().updateObject(this.entryEditing)
}
},
deleteEntry() {
this.$bvModal.hide(`edit-modal`)
this.$emit("delete-entry", this.entryEditing)
this.$bvModal.hide(this.modal_id)
useMealPlanStore().deleteObject(this.entryEditing)
},
selectMealType(event) {
this.missing_meal_type = false

View File

@@ -0,0 +1,101 @@
<template>
<div>
<b-button v-b-modal.id_import_tandoor_modal>{{ $t("Import into Tandoor") }}</b-button>
<b-modal class="modal" id="id_import_tandoor_modal" :title="$t('Import')" hide-footer>
<p>Tandoor ist eine OpenSource Rezeptverwaltungs Plattform</p>
<p>Bitte wähle aus ob du deinen eigenen Tandoor Server hast oder tandoor.dev nutzt.
</p>
<div class="justify-content-center text-center">
<b-form-group v-slot="{ ariaDescribedby }">
<b-form-radio-group
id="btn-radios-1"
v-model="import_mode"
:options="options"
:aria-describedby="ariaDescribedby"
name="radios-btn-default"
buttons
></b-form-radio-group>
</b-form-group>
</div>
<div v-if="import_mode === 'tandoor'">
<ol>
<li><a href="https://app.tandoor.dev/accounts/signup/" target="_blank" ref="nofollow">Hier</a> einen
Account anlegen<br/></li>
<li>
<b-button @click="importTandoor()">Import</b-button>
</li>
</ol>
</div>
<div v-if="import_mode === 'selfhosted'">
Deine Server URL (z.B. <code>https://tandoor.mydomain.com/</code>)
<b-input v-model="selfhosted_url"></b-input>
<b-button class="mt-2" :disabled="selfhosted_url === ''" @click="importSelfHosted()">Import</b-button>
</div>
<div class="row mt-3 text-left mb-3">
<p>Alternativ kannst du den Link zum Rezept in den Importer in deiner Tandoor Instanz kopieren.</p>
<a href="https://tandoor.dev" target="_blank" rel="nofollow">Jetzt mehr über Tandoor erfahren</a>
</div>
</b-modal>
</div>
</template>
<script>
import Vue from "vue";
import {BootstrapVue} from "bootstrap-vue";
import {ApiApiFactory} from "@/utils/openapi/api";
Vue.use(BootstrapVue)
export default {
name: 'ImportTandoor',
components: {},
props: {
recipe: Object,
},
data() {
return {
import_mode: 'tandoor',
options: [
{text: 'Tandoor.dev', value: 'tandoor'},
{text: 'Self-Hosted', value: 'selfhosted'},
],
selfhosted_url: '',
}
},
watch: {
selfhosted_url: function (newVal) {
window.localStorage.setItem('MY_TANDOOR_URL', newVal)
},
},
computed: {},
mounted() {
this.$i18n.locale = window.CUSTOM_LOCALE
let selfhosted_url = window.localStorage.getItem('MY_TANDOOR_URL')
if (selfhosted_url !== undefined) {
this.selfhosted_url = selfhosted_url
this.import_mode = 'selfhosted'
}
},
methods: {
importTandoor: function () {
location.href = 'https://app.tandoor.dev/data/import/url?url=' + location.href
},
importSelfHosted: function () {
this.selfhosted_url = this.selfhosted_url.replace('/search/', '')
let import_path = 'data/import/url?url='
if (!this.selfhosted_url.endsWith('/')) {
import_path = '/' + import_path
}
location.href = this.selfhosted_url + import_path + location.href
},
}
}
</script>

View File

@@ -14,7 +14,6 @@
<table class="table table-sm mb-0">
<ingredient-component v-for="i in steps.flatMap(s => s.ingredients)" v-bind:key="i.id"
:use_plural="true"
:detailed="true"
:ingredient="i"
:ingredient_factor="ingredient_factor"
@@ -78,6 +77,7 @@ const {ApiApiFactory} = require("@/utils/openapi/api")
import {StandardToasts} from "@/utils/utils"
import IngredientComponent from "@/components/IngredientComponent"
import LoadingSpinner from "@/components/LoadingSpinner"
import {useMealPlanStore} from "@/stores/MealPlanStore";
// import CustomInputSpinButton from "@/components/CustomInputSpinButton"
export default {
@@ -88,7 +88,7 @@ export default {
recipe: {required: true, type: Object},
servings: {type: Number, default: undefined},
modal_id: {required: true, type: Number},
mealplan: {type: Number, default: undefined},
mealplan: {type: Object, default: undefined},
list_recipe: {type: Number, default: undefined},
},
data() {
@@ -127,7 +127,7 @@ export default {
if (!this.recipe_servings) {
this.recipe_servings = result.data?.servings
}
this.steps.forEach(s => s.ingredients.filter(i => i.food.food_onhand === false).forEach(i => this.$set(i, 'checked', true)))
this.steps.forEach(s => s.ingredients.filter(i => i.food?.food_onhand === false).forEach(i => this.$set(i, 'checked', true)))
this.loading = false
})
.then(() => {
@@ -169,6 +169,9 @@ export default {
.then((result) => {
StandardToasts.makeStandardToast(this, StandardToasts.SUCCESS_CREATE)
this.$emit("finish")
if (this.mealplan !== undefined && this.mealplan !== null){
useMealPlanStore().plans[this.mealplan.id].shopping = true
}
})
.catch((err) => {
StandardToasts.makeStandardToast(this, StandardToasts.FAIL_CREATE, err)

View File

@@ -1,7 +1,7 @@
<template>
<div>
<template v-if="recipe && recipe.loading">
<b-card no-body v-hover>
<b-card no-body v-hover style="height: 100%">
<b-card-img-lazy style="height: 15vh; object-fit: cover" class="" :src="placeholder_image"
v-bind:alt="$t('Recipe_Image')" top></b-card-img-lazy>
@@ -19,54 +19,59 @@
</b-card>
</template>
<template v-else>
<b-card no-body v-hover v-if="recipe">
<b-card no-body v-hover v-if="recipe" style="height: 100%">
<a :href="this.recipe.id !== undefined ? resolveDjangoUrl('view_recipe', this.recipe.id) : null">
<b-card-img-lazy style="height: 15vh; object-fit: cover" class="" :src="recipe_image"
v-bind:alt="$t('Recipe_Image')" top></b-card-img-lazy>
<div
class="card-img-overlay h-100 d-flex flex-column justify-content-right float-right text-right pt-2 pr-1"
v-if="show_context_menu">
<a>
<recipe-context-menu :recipe="recipe" class="float-right" :disabled_options="context_disabled_options"
v-if="recipe !== null"></recipe-context-menu>
</a>
</div>
<div class="card-img-overlay w-50 d-flex flex-column justify-content-left float-left text-left pt-2"
v-if="recipe.working_time !== 0 || recipe.waiting_time !== 0">
<b-badge pill variant="light" class="mt-1 font-weight-normal" v-if="recipe.working_time !== 0">
<i
class="fa fa-clock"></i> {{ working_time }}
</b-badge>
<b-badge pill variant="secondary" class="mt-1 font-weight-normal"
v-if="recipe.waiting_time !== 0">
<i class="fa fa-pause"></i> {{ waiting_time }}
</b-badge>
<div class="content">
<div class="content-overlay" v-if="recipe.description !== null && recipe.description !== ''"></div>
<b-card-img-lazy style="height: 15vh; object-fit: cover" class="" :src="recipe_image"
v-bind:alt="$t('Recipe_Image')" top></b-card-img-lazy>
<div class="content-details" >
<p class="content-text">
{{ recipe.description }}
</p>
</div>
<div class="card-img-overlay d-flex flex-column justify-content-left float-left text-left pt-2" style="width:40%"
v-if="recipe.working_time !== 0 || recipe.waiting_time !== 0">
<b-badge pill variant="light" class="mt-1 font-weight-normal" v-if="recipe.working_time !== 0">
<i
class="fa fa-clock"></i> {{ working_time }}
</b-badge>
<b-badge pill variant="secondary" class="mt-1 font-weight-normal"
v-if="recipe.waiting_time !== 0">
<i class="fa fa-pause"></i> {{ waiting_time }}
</b-badge>
</div>
</div>
</a>
<b-card-body class="p-4">
<h6>
<a :href="this.recipe.id !== undefined ? resolveDjangoUrl('view_recipe', this.recipe.id) : null">
<b-card-body class="p-2 pl-3 pr-3">
<div class="d-flex flex-row">
<div class="flex-grow-1">
<a :href="this.recipe.id !== undefined ? resolveDjangoUrl('view_recipe', this.recipe.id) : null" class="text-body font-weight-bold two-row-text">
<template v-if="recipe !== null">{{ recipe.name }}</template>
<template v-else>{{ meal_plan.title }}</template>
</a>
</h6>
</div>
<div class="justify-content-end">
<recipe-context-menu :recipe="recipe" class="justify-content-end float-right align-items-end pr-0"
:disabled_options="context_disabled_options"
v-if="recipe !== null"></recipe-context-menu>
</div>
</div>
<b-card-text style="text-overflow: ellipsis">
<template v-if="recipe !== null">
<recipe-rating :recipe="recipe"></recipe-rating>
<template v-if="recipe.description !== null && recipe.description !== undefined">
<span v-if="recipe.description.length > text_length">
{{ recipe.description.substr(0, text_length) + "\u2026" }}
</span>
<span v-if="recipe.description.length <= text_length">
{{ recipe.description }}
</span>
</template>
<p class="mt-1">
<div v-if="show_detail">
{{ recipe.description }}
</div>
<p class="mt-1 mb-1">
<last-cooked :recipe="recipe"></last-cooked>
<keywords-component :recipe="recipe"
<keywords-component :recipe="recipe" :limit="3"
style="margin-top: 4px; position: relative; z-index: 3;"></keywords-component>
</p>
<transition name="fade" mode="in-out">
@@ -75,29 +80,46 @@
<h6 class="card-title"><i class="fas fa-pepper-hot"></i> {{ $t("Ingredients") }}
</h6>
<ingredients-card
:steps="recipe.steps"
:header="false"
:detailed="false"
:servings="recipe.servings"
:use_plural="use_plural" />
</div>
</div>
</transition>
<ingredients-card
:steps="recipe.steps"
:header="false"
:detailed="false"
:servings="recipe.servings"/>
</div>
</div>
</transition>
<b-badge pill variant="info" v-if="!recipe.internal">{{ $t("External") }}</b-badge>
</template>
<template v-else>{{ meal_plan.note }}</template>
</b-card-text>
</b-card-body>
<b-card-footer v-if="footer_text !== undefined"><i v-bind:class="footer_icon"></i> {{ footer_text }}
</b-card-footer>
</b-card>
</template>
</div>
<!--
<recipe-rating :recipe="recipe"></recipe-rating>
<template v-if="recipe.description !== null && recipe.description !== undefined">
<span v-if="recipe.description.length > text_length">
{{ recipe.description.substr(0, text_length) + "\u2026" }}
</span>
<span v-if="recipe.description.length <= text_length">
{{ recipe.description }}
</span>
</template>
<b-card-footer v-if="footer_text !== undefined"><i v-bind:class="footer_icon"></i> {{ footer_text }}
</b-card-footer>
<template v-else>{{ meal_plan.note }}</template>
-->
</template>
<script>
@@ -117,7 +139,6 @@ export default {
mixins: [ResolveUrlMixin],
components: {
LastCooked,
RecipeRating,
KeywordsComponent,
"recipe-context-menu": RecipeContextMenu,
IngredientsCard
@@ -125,7 +146,7 @@ export default {
props: {
recipe: Object,
meal_plan: Object,
use_plural: { type: Boolean, default: false},
use_plural: {type: Boolean, default: false},
footer_text: String,
footer_icon: String,
detailed: {type: Boolean, default: true},
@@ -144,13 +165,6 @@ export default {
show_detail: function () {
return this.recipe?.steps !== undefined && this.detailed
},
text_length: function () {
if (this.show_detail) {
return 200
} else {
return 120
}
},
recipe_image: function () {
if (this.recipe == null || this.recipe.image === null) {
return window.IMAGE_PLACEHOLDER
@@ -191,4 +205,79 @@ export default {
{
opacity: 0;
}
.two-row-text {
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 2; /* number of lines to show */
line-clamp: 2;
-webkit-box-orient: vertical;
}
.content {
position: relative;
margin: auto;
overflow: visible;
}
.content .content-overlay {
background: rgba(0, 0, 0, 0.7);
position: absolute;
height: 99%;
width: 100%;
left: 0;
top: 0;
bottom: 0;
right: 0;
opacity: 0;
-webkit-transition: all 0.4s ease-in-out 0s;
-moz-transition: all 0.4s ease-in-out 0s;
transition: all 0.4s ease-in-out 0s;
}
.content:hover .content-overlay {
opacity: 1;
}
.content-details {
position: absolute;
text-align: center;
padding-left: 1em;
padding-right: 1em;
width: 100%;
top: 50%;
left: 50%;
opacity: 0;
-webkit-transform: translate(-50%, -50%);
-moz-transform: translate(-50%, -50%);
transform: translate(-50%, -50%);
-webkit-transition: all 0.3s ease-in-out 0s;
-moz-transition: all 0.3s ease-in-out 0s;
transition: all 0.3s ease-in-out 0s;
}
.content:hover .content-details {
top: 50%;
left: 50%;
opacity: 1;
}
.content-details h3 {
color: #fff;
font-weight: 500;
letter-spacing: 0.15em;
margin-bottom: 0.5em;
text-transform: uppercase;
}
.content-details p {
color: #fff;
font-size: 0.8em;
}
.fadeIn-bottom {
top: 80%;
}
</style>

View File

@@ -1,12 +1,12 @@
<template>
<div>
<div class="dropdown d-print-none">
<a class="btn shadow-none" href="javascript:void(0);" role="button" id="dropdownMenuLink"
<a class="btn shadow-none pr-0 pl-0" href="javascript:void(0);" role="button" id="dropdownMenuLink"
data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<i class="fas fa-ellipsis-v fa-lg"></i>
</a>
<div class="dropdown-menu dropdown-menu-right" aria-labelledby="dropdownMenuLink">
<div class="dropdown-menu dropdown-menu-right" aria-labelledby="dropdownMenuLink" >
<a class="dropdown-item" :href="resolveDjangoUrl('edit_recipe', recipe.id)" v-if="!disabled_options.edit"><i
class="fas fa-pencil-alt fa-fw"></i> {{ $t("Edit") }}</a>
@@ -106,6 +106,7 @@ import ShoppingModal from "@/components/Modals/ShoppingModal"
import moment from "moment"
import Vue from "vue"
import {ApiApiFactory} from "@/utils/openapi/api"
import {useMealPlanStore} from "@/stores/MealPlanStore";
Vue.prototype.moment = moment
@@ -191,6 +192,7 @@ export default {
apiClient
.createMealPlan(entry)
.then((result) => {
useMealPlanStore().plans.push(result.data)
this.$bvModal.hide(`modal-meal-plan_${this.modal_id}`)
if (reviewshopping) {
this.mealplan = result.data.id

View File

@@ -24,7 +24,7 @@
<span v-if="user_preferences.shopping_auto_sync < 1">{{ $t('Disable') }}</span>
</div>
<br/>
<b-button class="btn btn-sm" @click="user_preferences.shopping_auto_sync = 0">{{ $t('Disabled') }}</b-button>
<b-button class="btn btn-sm" @click="user_preferences.shopping_auto_sync = 0; updateSettings(false)">{{ $t('Disabled') }}</b-button>
</b-form-group>
<b-form-group :description="$t('mealplan_autoadd_shopping_desc')">

View File

@@ -35,7 +35,7 @@
<div class="col col-md-4"
v-if="step.ingredients.length > 0 && (recipe.steps.length > 1 || force_ingredients)">
<table class="table table-sm">
<ingredients-card :steps="[step]" :ingredient_factor="ingredient_factor" :use_plural="use_plural"
<ingredients-card :steps="[step]" :ingredient_factor="ingredient_factor"
@checked-state-changed="$emit('checked-state-changed', $event)"/>
</table>
</div>

View File

@@ -459,11 +459,24 @@
"Message": "Besked",
"Sticky_Nav": "Fastlåst navigation",
"reset_food_inheritance": "Nulstil nedarvning",
"Plural": "",
"plural_short": "",
"Use_Plural_Unit_Always": "",
"Use_Plural_Unit_Simple": "",
"Use_Plural_Food_Always": "",
"Use_Plural_Food_Simple": "",
"plural_usage_info": ""
"Plural": "Flertal",
"plural_short": "flertal",
"Use_Plural_Unit_Always": "Benyt altid flertalsform for enheder",
"Use_Plural_Unit_Simple": "Brug flertalsform dynamisk for enheder",
"Use_Plural_Food_Always": "Brug altid flertalsform for mad",
"Use_Plural_Food_Simple": "Brug flertalsform dynamisk for mad",
"plural_usage_info": "Brug flertalsform for enheder og mad på denne placering.",
"Original_Text": "Original tekst",
"Import Recipe": "Importer opskrift",
"Amount": "Mængde",
"Split_All_Steps": "Opdel rækker i separate trin.",
"Create Recipe": "Opret opskrift",
"Description_Replace": "Erstat beskrivelse",
"Instruction_Replace": "Erstat instruktion",
"Auto_Sort_Help": "Flyt alle ingredienser til mest egnede trin.",
"Auto_Sort": "Sortér automatisk",
"Unpin": "Frigør",
"PinnedConfirmation": "{recipe} er fastgjort.",
"UnpinnedConfirmation": "{recipe} er frigjort.",
"Combine_All_Steps": "Kombiner alle trin til ét felt."
}

View File

@@ -367,7 +367,7 @@
"desc": "Absteigend",
"book_filter_help": "Schließt zusätzlich zu den manuell hinzugefügten Rezepten, alle Rezepte die dem Filter entsprechen ein.",
"recipe_name": "Rezeptname",
"paste_ingredients_placeholder": "Zutatenliste hier einfügen",
"paste_ingredients_placeholder": "Zutatenliste hier einfügen...",
"ingredient_list": "Zutatenliste",
"filter": "Filter",
"err_deleting_protected_resource": "Das zu löschende Objekt wird noch verwendet und kann nicht gelöscht werden.",
@@ -477,5 +477,7 @@
"Auto_Sort_Help": "Verschiebe alle Zutaten zu dem Schritt, der am Besten passt.",
"Combine_All_Steps": "Fasse alle Schritte in einem einzelnem Feld zusammen.",
"reset_children_help": "Überschreibe alle Kinder mit den Werten der vererbten Felder. Die vererbten Felder der Kinder werden als vererbte Felder gesetzt, es sei denn, das Kind-Vererben-Feld ist gesetzt.",
"Unpin": "Lösen"
"Unpin": "Lösen",
"Amount": "Menge",
"Original_Text": "Originaltext"
}

View File

@@ -118,7 +118,7 @@
"Image": "Image",
"Delete": "Delete",
"Open": "Open",
"Ok": "Open",
"Ok": "Ok",
"Save": "Save",
"Step": "Step",
"Search": "Search",
@@ -476,5 +476,7 @@
"Use_Plural_Unit_Simple": "Use plural form for unit dynamically",
"Use_Plural_Food_Always": "Use plural form for food always",
"Use_Plural_Food_Simple": "Use plural form for food dynamically",
"plural_usage_info": "Use the plural form for units and food inside this space."
"plural_usage_info": "Use the plural form for units and food inside this space.",
"Create Recipe": "Create Recipe",
"Import Recipe": "Import Recipe"
}

View File

@@ -167,8 +167,8 @@
"Create_New_Keyword": "Añadir nueva Etiqueta",
"Create_New_Unit": "Añadir nueva unidad",
"Create_New_Meal_Type": "Añadir nuevo Tipo de Comida",
"and_up": "",
"and_down": "",
"and_up": "& Arriba",
"and_down": "& Abajo",
"Instructions": "Instrucciones",
"Unrated": "Sin puntuar",
"Automate": "Automatizar",
@@ -443,5 +443,14 @@
"Use_Plural_Unit_Simple": "",
"Use_Plural_Food_Always": "",
"Use_Plural_Food_Simple": "",
"plural_usage_info": ""
"plural_usage_info": "",
"Original_Text": "Texto original",
"Use_Fractions_Help": "Convertir automáticamente los decimales en fracciones al ver una receta.",
"Description_Replace": "Reemplazar Descripción",
"Instruction_Replace": "Reemplazar Instrucción",
"plan_share_desc": "Las Nuevas entradas del Plan de Comidas se compartirán automáticamente con los usuarios seleccionados.",
"Auto_Sort": "Ordenar Automáticamente",
"Auto_Sort_Help": "Mueva todos los ingredientes al paso que mejor se adapte.",
"Unpin": "Desanclar",
"Amount": "Cantidad"
}

View File

@@ -1,5 +1,5 @@
{
"err_fetching_resource": "Erreur lors de la récupération dune ressource !",
"err_fetching_resource": "Il y a eu une erreur lors de la récupération d'une ressource!",
"err_creating_resource": "Erreur lors de la création dune ressource !",
"err_updating_resource": "Erreur lors de la mise à jour dune ressource !",
"err_deleting_resource": "Erreur lors de la suppression dune ressource !",
@@ -12,7 +12,7 @@
"convert_internal": "Convertir en recette interne",
"show_only_internal": "Montrer uniquement les recettes internes",
"Log_Recipe_Cooking": "Marquer la recette comme cuisinée",
"External_Recipe_Image": "Image externe de recette",
"External_Recipe_Image": "Image de recette externe",
"Add_to_Shopping": "Ajouter à la liste de courses",
"Add_to_Plan": "Ajouter au menu",
"Step_start_time": "Heure de début de létape",
@@ -22,7 +22,7 @@
"Meal_Plan": "Menu de la semaine",
"Select_Book": "Sélectionner le livre",
"Recipe_Image": "Image de la recette",
"Import_finished": "Importation finie",
"Import_finished": "Importation terminée",
"View_Recipes": "Voir les recettes",
"Log_Cooking": "Marquer comme cuisiné",
"New_Recipe": "Nouvelle recette",
@@ -30,7 +30,7 @@
"Reset_Search": "Réinitialiser la recherche",
"Recently_Viewed": "Vu récemment",
"Load_More": "Charger plus",
"Keywords": "Mots-clés",
"Keywords": "mots-clés",
"Books": "Livres",
"Proteins": "Protéines",
"Fats": "Matières grasses",
@@ -62,11 +62,11 @@
"Size": "Taille",
"Files": "Fichiers",
"File": "Fichier",
"Edit": "Modifier",
"Edit": "modifier",
"Cancel": "Annuler",
"Delete": "Supprimer",
"Open": "Ouvrir",
"Ok": "Ouvrir",
"Ok": "D'accord",
"Save": "Sauvegarder",
"Step": "Étape",
"Search": "Rechercher",
@@ -78,12 +78,12 @@
"Information": "Information",
"Download": "Télécharger",
"Create": "Créer",
"show_split_screen": "Vue Séparée",
"show_split_screen": "Vue séparée",
"New_Keyword": "Nouveau mot-clé",
"Delete_Keyword": "Supprimer mot-clé",
"Move_Keyword": "Déplacer mot-clé",
"Merge_Keyword": "Fusionner mots-clés",
"Hide_Recipes": "Cacher recettes",
"Delete_Keyword": "Supprimer le mot-clé",
"Move_Keyword": "Déplacer le mot-clé",
"Merge_Keyword": "Fusionner le mot-clé",
"Hide_Recipes": "Cacher les recettes",
"Advanced Search Settings": "Paramètres de recherche avancée",
"View": "Voir",
"Recipes": "Recettes",
@@ -96,8 +96,8 @@
"delete_confirmation": "Êtes-vous sûr de vouloir supprimer {source} ?",
"Shopping_Category": "Catégorie de courses",
"Ignore_Shopping": "Ignorer les courses",
"Edit_Food": "Modifier aliment",
"Move_Food": "Déplacer aliment",
"Edit_Food": "Modifier laliment",
"Move_Food": "Déplacer laliment",
"New_Food": "Nouvel aliment",
"Hide_Food": "Cacher laliment",
"Delete_Food": "Supprimer laliment",
@@ -113,13 +113,13 @@
"Description": "Description",
"Recipe": "Recette",
"tree_root": "Racine de larbre",
"Edit_Keyword": "Modifier mot-clé",
"Edit_Keyword": "Modifier le mot-clé",
"Hide_Keywords": "Cacher le mot-clé",
"move_selection": "Sélectionner un parent {type} pour y déplacer {source}.",
"merge_selection": "Remplace toutes les occurrences de {source} par {type}.",
"merge_selection": "Remplacer toutes les occurrences de {source} par {type}.",
"move_title": "Déplacer {type}",
"del_confirmation_tree": "Êtes-vous sûr de vouloir supprimer {source} et tous ses enfants ?",
"warning_feature_beta": "Cette fonctionnalité est actuellement en phase BETA (test). Veuillez vous attendre à des bugs et éventuellement à des modifications conséquentes à lavenir (perte éventuelle de données liées à la fonctionnalité) lorsque vous utilisez cette fonctionnalité.",
"warning_feature_beta": "Cette fonctionnalité est actuellement en état BETA (de test). Veuillez vous attendre à des bogues et éventuellement à des modifications majeures à l'avenir (pouvant entraîner une perte de données liées à la fonctionnalité) lors de l'utilisation de cette fonctionnalité.",
"confirm_delete": "Voulez-vous vraiment supprimer {objet} ?",
"Note": "Notes",
"Add_Step": "Ajouter une étape",
@@ -189,7 +189,7 @@
"Show_as_header": "Montrer comme en-tête",
"Hide_as_header": "Cacher comme en-tête",
"Copy_template_reference": "Copier la référence du modèle",
"Edit_Recipe": "Modifier une Recette",
"Edit_Recipe": "Modifier la recette",
"Move_Up": "Monter",
"Time": "Temps",
"Coming_Soon": "Bientôt disponible",
@@ -225,14 +225,14 @@
"Clear": "Supprimer",
"AddToShopping": "Ajouter à la liste de courses",
"IngredientInShopping": "Cet ingrédient est dans votre liste de courses.",
"NotInShopping": "{food} nest pas dans votre liste de courses.",
"NotInShopping": "Laliment {food} nest pas dans votre liste de courses.",
"OnHand": "Disponible actuellement",
"FoodNotOnHand": "Lingrédient {food} nest pas disponible.",
"FoodNotOnHand": "Laliment {food} nest pas disponible.",
"Planner": "Planificateur",
"Planner_Settings": "Paramètres du planificateur",
"AddFoodToShopping": "Ajouter lingrédient {food} à votre liste de courses",
"DeleteShoppingConfirm": "Êtes-vous sûr(e) de vouloir retirer tous les ingrédients {food} de votre liste de courses ?",
"IgnoredFood": "Lingrédient {food} est paramétré pour ignorer les courses.",
"AddFoodToShopping": "Ajouter laliment {food} à votre liste de courses",
"DeleteShoppingConfirm": "Êtes-vous sûr(e) de vouloir supprimer tous les aliments {food} de votre liste de courses?",
"IgnoredFood": "Ignorer les courses est paramétré pour laliment {food}.",
"Inherit": "Hériter",
"InheritFields": "Hériter les valeurs des champs",
"FoodInherit": "Ingrédient hérité",
@@ -240,7 +240,7 @@
"GroupBy": "Grouper par",
"SupermarketCategoriesOnly": "Catégories de supermarché uniquement",
"MoveCategory": "Déplacer vers : ",
"IgnoreThis": "Ne jamais ajouter l'ingrédient {food} aux courses",
"IgnoreThis": "Ne jamais ajouter automatiquement laliment {food} aux courses",
"DelayFor": "Retard de {hours} heures",
"Warning": "Avertissement",
"InheritWarning": "L'ingrédient {food} est un héritage, les changements pourraient ne pas être conservés.",
@@ -275,15 +275,15 @@
"DelayUntil": "Retard jusqu'à",
"mark_complete": "Marque comme terminé",
"QuickEntry": "Entrée rapide",
"shopping_add_onhand_desc": "Marquer les aliments comme \"disponibles\" lorsqu'ils sont cochés sur la liste des courses.",
"shopping_add_onhand_desc": "Marquer les aliments comme « disponibles » lorsqu'ils sont cochés sur la liste des courses.",
"shopping_add_onhand": "Disponible par défaut",
"related_recipes": "Recettes connexes",
"today_recipes": "Recettes du jour",
"Search Settings": "Paramètres de recherche",
"FoodOnHand": "Lingrédient {food} est disponible.",
"FoodOnHand": "Laliment {food} est disponible.",
"Undefined": "Indéfini",
"Create_Meal_Plan_Entry": "Créer une entrée de menu",
"RemoveFoodFromShopping": "Retirer lingrédient {food} de votre liste de courses",
"RemoveFoodFromShopping": "Supprimer laliment {food} de votre liste de courses",
"left_handed": "Mode gaucher",
"left_handed_help": "Optimise linterface utilisateur pour une utilisation avec la main gauche.",
"Custom Filter": "Filtre personnalisé",
@@ -298,9 +298,9 @@
"paste_ingredients": "Copier les ingrédients",
"ingredient_list": "Liste des ingrédients",
"search_no_recipes": "Aucune recette trouvée !",
"substitute_siblings_help": "Tous les ingrédients qui partagent un parent avec cette ingrédient sont considérés comme des substituts.",
"OnHand_help": "L'ingrédient est dans l'inventaire et ne sera pas automatiquement ajouté à la liste de courses. Le status actuel est partagé avec les utilisateurs de la liste.",
"ignore_shopping_help": "Ne jamais ajouter l'ingrédient à la liste de courses (ex: eau)",
"substitute_siblings_help": "Tous les aliments qui partagent un parent avec cet aliment sont considérés comme des substituts.",
"OnHand_help": "Laliment est dans linventaire et ne sera pas automatiquement ajouté à la liste de courses. Létat de disponibilité est partagé avec les utilisateurs de la liste.",
"ignore_shopping_help": "Ne jamais ajouter daliment à la liste de courses (ex. : eau)",
"food_recipe_help": "Ajouter un lien vers la recette ici incluera cette recette dans n'importe qu'elle autre recette qui utilise cet ingrédient",
"shopping_category_help": "Les supermarchés peuvent être triés et filtrés par catégorie d'ingrédients selon la disposition des rayons.",
"Units": "Unités",
@@ -310,7 +310,7 @@
"Supermarkets": "Supermarchés",
"User": "Utilisateur",
"Keyword": "Mot-clé",
"Foods": "Ingrédients",
"Foods": "Aliments",
"enable_expert": "Activer le mode expert",
"show_rating": "Afficher les notes",
"asc": "Ordre croissant",
@@ -324,7 +324,7 @@
"advanced": "Avancé",
"fields": "Champs",
"show_keywords": "Afficher les mots-clés",
"show_foods": "Afficher les ingrédients",
"show_foods": "Afficher les aliments",
"show_books": "Afficher les livres",
"show_units": "Afficher les unités",
"show_filters": "Afficher les filtres",
@@ -333,10 +333,10 @@
"click_image_import": "Cliquez sur l'image que vous souhaitez importer pour cette recette",
"select_unit": "Sélectionner Unité",
"Select_App_To_Import": "Veuillez sélectionner une App pour importer depuis",
"err_deleting_protected_resource": "L'objet que vous essayez de supprimer est toujours utilisé et ne peut pas être supprimé.",
"err_deleting_protected_resource": "Lobjet que vous essayez de supprimer est toujours utilisé et ne peut pas être supprimé.",
"Are_You_Sure": "Etes-vous sûr ?",
"filter": "Filtre",
"Ingredient Editor": "Éditeur d'ingrédients",
"Ingredient Editor": "Éditeur dingrédients",
"advanced_search_settings": "Paramètres de recherche avancée",
"nothing_planned_today": "Vous n'avez rien de prévu pour aujourd'hui !",
"Pinned": "Epinglé",
@@ -355,7 +355,7 @@
"Options": "Options",
"additional_options": "Options Supplémentaires",
"Website": "Site",
"App": "App",
"App": "Appli",
"Click_To_Edit": "Cliquer pour éditer",
"reset_children": "Réinitialiser l'héritage enfant",
"created_on": "Créé le",
@@ -380,7 +380,7 @@
"no_more_images_found": "Pas d'images supplémentaires trouvées sur le site.",
"sql_debug": "Débogage de la base SQL",
"last_cooked": "Dernière recette utilisée",
"times_cooked": "Temps de cuisson",
"times_cooked": "Nombre de fois cuisiné",
"show_sortby": "Trier par",
"Hours": "Heures",
"Days": "Jours",
@@ -395,7 +395,7 @@
"Default_Unit": "Unité par défaut",
"Hour": "Heure",
"Day": "Jour",
"food_inherit_info": "Champs sur les ingrédients qui doivent être hérité par défaut.",
"food_inherit_info": "Champs sur les aliments à hériter par défaut.",
"Invites": "Invitations",
"paste_json": "Collez une source json ou html pour charger la recette.",
"warning_space_delete": "Vous pouvez supprimer votre groupe ainsi que toutes les recettes, listes de courses, menus et autres choses que vous avez créés. Vous ne pourrez pas revenir sur cette suppression ! Êtes-vous sûr de vouloir le faire ?",
@@ -403,11 +403,62 @@
"import_duplicates": "Pour éviter les doublons, les recettes de même nom seront ignorées. Cocher la case pour tout importer.",
"Account": "Compte",
"Change_Password": "Modifier le mot de passe",
"Plural": "",
"plural_short": "",
"Use_Plural_Unit_Always": "",
"Use_Plural_Unit_Simple": "",
"Use_Plural_Food_Always": "",
"Use_Plural_Food_Simple": "",
"plural_usage_info": ""
"Plural": "Pluriel",
"plural_short": "pluriel",
"Use_Plural_Unit_Always": "Toujours utiliser la forme plurielle pour les unités",
"Use_Plural_Unit_Simple": "Utiliser la forme plurielle pour les unités de manière dynamique",
"Use_Plural_Food_Always": "Toujours utiliser la forme plurielle pour les aliments",
"Use_Plural_Food_Simple": "Utiliser la forme plurielle pour les aliments de manière dynamique",
"plural_usage_info": "Utiliser la forme plurielle pour les unités et les aliments dans ce groupe.",
"Planned": "Planifié",
"Amount": "Quantité",
"Original_Text": "Texte dorigine",
"Use_Fractions": "Utiliser les fractions",
"Use_Fractions_Help": "Convertir les décimales en fractions automatiquement lors de la visualisation dune recette.",
"Message": "Message",
"Sticky_Nav_Help": "Toujours afficher le menu de navigation en haut de lécran.",
"Combine_All_Steps": "Combiner toutes les étapes en un seul champ.",
"facet_count_info": "Afficher les compteurs de recette sur les filtres de recherche.",
"Decimals": "Décimales",
"plan_share_desc": "Les nouvelles entrées de menu de la semaine seront partagées automatiquement avec des utilisateurs sélectionnés.",
"Use_Kj": "Utiliser kJ au lieu de kcal",
"Manage_Emails": "Gérer les e-mails",
"select_food": "Séletionner laliment",
"Toggle": "Basculer",
"Theme": "Thème",
"Import_Supported": "Importation prise en charge",
"Auto_Sort": "Tri automatique",
"Auto_Sort_Help": "Déplacer tous les ingrédients à létape la mieux adaptée.",
"reusable_help_text": "Le lien dinvitation doit-il être utilisable par plus dun utilisateur.",
"date_viewed": "Dernier vu",
"Username": "Nom dutilisateur",
"First_name": "Prénom",
"Last_name": "Nom",
"Disabled": "Désactivé",
"Disable": "Désactiver",
"Export_Supported": "Exportation prise en charge",
"Recipes_In_Import": "Recettes dans votre fichier dimportation",
"Import_Error": "Une erreur est survenue pendant votre importation. Veuillez développer les détails au bas de la page pour la consulter.",
"Valid Until": "Valide jusquau",
"Create Food": "Créer un aliment",
"create_food_desc": "Créer un aliment et le relier par une lien à cette recette.",
"remember_hours": "Horaires à retenir",
"Ingredient Overview": "Aperçu des ingrédients",
"parameter_count": "Paramètres {count}",
"show_ingredient_overview": "Afficher une liste de tous les ingrédients au début de la recette.",
"Import_Not_Yet_Supported": "Importation pas encore prise en charge",
"Export_Not_Yet_Supported": "Exportation pas encore prise en charge",
"Import_Result_Info": "{imported} sur {total} recettes ont été importées",
"API": "API",
"not": "pas",
"Create Recipe": "Créer une recette",
"Import Recipe": "Importer une recette",
"Copy Token": "Copier le jeton",
"Description_Replace": "Remplacer la Description",
"Cosmetic": "Cosmétique",
"explain": "Expliquer",
"Unpin": "Détacher",
"Split_All_Steps": "Diviser toutes les lignes en étapes séparées.",
"Warning_Delete_Supermarket_Category": "Supprimer une catégorie de supermarché supprimera également toutes les relations avec les aliments. Êtes-vous sûr ?",
"Instruction_Replace": "Instruction Remplacer"
}

View File

@@ -1,8 +1,8 @@
{
"warning_feature_beta": "Fitur ini saat ini dalam status BETA (pengujian). Harap perkirakan bug dan kemungkinan kerusakan perubahan di masa mendatang (mungkin kehilangan data terkait fitur) saat menggunakan fitur ini.",
"err_fetching_resource": "Terjadi kesalahan saat mengambil sumber daya!",
"warning_feature_beta": "Fitur ini saat ini dalam status BETA (pengujian). Mungkin terdapat bug dan perubahan yang penting di masa mendatang (sehingga mungkin terjadi kehilangan data terkait fitur) saat menggunakan fitur ini.",
"err_fetching_resource": "Terjadi kesalahan saat memperoleh sumber daya!",
"err_creating_resource": "Terjadi kesalahan saat membuat sumber daya!",
"err_updating_resource": "Terjadi kesalahan saat mengupdate sumber daya!",
"err_updating_resource": "Terjadi kesalahan saat memperbarui sumber daya!",
"err_deleting_resource": "Terjadi kesalahan saat menghapus sumber daya!",
"err_deleting_protected_resource": "Objek yang Anda coba hapus masih digunakan dan tidak dapat dihapus.",
"err_moving_resource": "Terjadi kesalahan saat memindahkan sumber daya!",

View File

@@ -74,7 +74,7 @@
"Edit": "Modifica",
"Delete": "Elimina",
"Open": "Apri",
"Ok": "Apri",
"Ok": "Ok",
"Save": "Salva",
"Step": "Step",
"Search": "Cerca",
@@ -462,5 +462,9 @@
"shopping_category_help": "I supermercati possono essere ordinati e filtrati per categoria di spesa seguendo la disposizione degli scaffali.",
"food_recipe_help": "Collegando qui una ricetta, includerà la stessa in ogni altra ricetta che usa questo alimento",
"warning_duplicate_filter": "Avviso: a causa di limitazioni tecniche, usare più filtri di ricerca della stessa combinazione (and/or/not) potrebbe portare a risultati inaspettati.",
"Warning_Delete_Supermarket_Category": "L'eliminazione di una categoria di supermercato comporta anche l'eliminazione di tutte le relazioni con gli alimenti. Sei sicuro?"
"Warning_Delete_Supermarket_Category": "L'eliminazione di una categoria di supermercato comporta anche l'eliminazione di tutte le relazioni con gli alimenti. Sei sicuro?",
"Original_Text": "Testo originale",
"search_rank": "Posizione di ricerca",
"make_now": "Fai ora",
"Amount": "Quantità"
}

View File

@@ -74,7 +74,7 @@
"success_deleting_resource": "Hulpbron succesvol verwijderd!",
"Cancel": "Annuleer",
"Delete": "Verwijder",
"Ok": "Open",
"Ok": "Ok",
"Load_More": "Laad meer",
"Manage_Books": "Beheer boeken",
"Create": "Voeg toe",
@@ -162,7 +162,7 @@
"del_confirmation_tree": "Weet je zeker dat je {source} en al zijn kinderen wil verwijderen?",
"Create_New_Food": "Voeg nieuw Eten toe",
"Time": "Tijd",
"warning_feature_beta": "Deze functie zit op dit moment in de BETA (test) fase. Verwacht hier bugs en toekomstige wijzigingen die tot het verlies van data gaan leiden bij het gebruik.",
"warning_feature_beta": "Deze functie zit op dit moment in de BETA (test) fase. Verwacht hier bugs en toekomstige wijzigingen die tot het verlies van data kunnen leiden bij het gebruik.",
"Table_of_Contents": "Inhoudsopgave",
"Create_New_Meal_Type": "Voeg Nieuw Maaltijdtype toe",
"Empty": "Leeg",
@@ -376,7 +376,7 @@
"substitute_children_help": "Alle ingrediënten die kinderen zijn van dit ingrediënt worden beschouwd als vervangers.",
"SubstituteOnHand": "Je hebt een vervanger op voorraad.",
"ChildInheritFields": "Kinderen erven velden",
"InheritFields_help": "De waarden van deze velden worden geërfd van een ouder (uitzondering: lege boodschappencategorieën)",
"InheritFields_help": "De waarden van deze velden worden overgenomen van de bovenliggende waarden (uitzondering: lege boodschappencategorieën)",
"no_pinned_recipes": "Je hebt geen vastgepinde recepten!",
"Internal": "Interne",
"Reset": "Herstel",
@@ -467,11 +467,18 @@
"facet_count_info": "Geef receptenaantal bij zoekfilters weer.",
"Split_All_Steps": "Splits alle rijen in apparte stappen.",
"Combine_All_Steps": "Voeg alle stappen samen tot een veld.",
"Plural": "",
"plural_short": "",
"Use_Plural_Unit_Always": "",
"Use_Plural_Unit_Simple": "",
"Use_Plural_Food_Always": "",
"Use_Plural_Food_Simple": "",
"plural_usage_info": ""
"Plural": "Meervoud",
"plural_short": "meervoud",
"Use_Plural_Unit_Always": "Gebruik altijd de meervoudsvorm voor eenheden",
"Use_Plural_Unit_Simple": "Gebruik meervoudsvorm voor eenheden dynamisch",
"Use_Plural_Food_Always": "Gebruik altijd meervoudsvorm voor voedsel",
"Use_Plural_Food_Simple": "Gebruik meervoudsvorm voor voedsels dynamisch",
"plural_usage_info": "Gebruik de meervoudsvorm voor eenheden en voedsels in deze ruimte.",
"Amount": "Hoeveelheid",
"Original_Text": "Originele tekst",
"reset_food_inheritance_info": "Herstel alle voedingsmiddelen naar de standaard overgenomen velden en hun bovenliggende waarden.",
"Description_Replace": "Vervang beschrijving",
"Instruction_Replace": "Vervang instructie",
"Auto_Sort_Help": "Verplaats alle ingrediënten naar de best passende stap.",
"Auto_Sort": "Automatisch sorteren"
}

View File

@@ -478,5 +478,7 @@
"Amount": "Ilość",
"Original_Text": "Tekst oryginalny",
"Description_Replace": "Zmień opis",
"Instruction_Replace": "Zmień instrukcję"
"Instruction_Replace": "Zmień instrukcję",
"Import Recipe": "Importuj przepis",
"Create Recipe": "Utwórz przepis"
}

View File

@@ -150,15 +150,15 @@
"delete_title": "Deletar {type}",
"create_title": "Novo {type}",
"edit_title": "",
"Name": "",
"Type": "",
"Description": "",
"Recipe": "",
"Name": "Nome",
"Type": "Tipo",
"Description": "Descrição",
"Recipe": "Receita",
"tree_root": "",
"Icon": "",
"Unit": "",
"No_Results": "",
"New_Unit": "",
"Icon": "Ícone",
"Unit": "Unidade",
"No_Results": "Sem Resultados",
"New_Unit": "Nova Unidade",
"Create_New_Shopping Category": "",
"Create_New_Food": "",
"Create_New_Keyword": "",
@@ -394,5 +394,9 @@
"Use_Plural_Unit_Simple": "",
"Use_Plural_Food_Always": "",
"Use_Plural_Food_Simple": "",
"plural_usage_info": ""
"plural_usage_info": "",
"Amount": "Quantidade",
"Description_Replace": "Substituir Descrição",
"Decimals": "Decimais",
"Instruction_Replace": "Substituir Instrução"
}

View File

@@ -328,7 +328,7 @@
"remember_search": "Kom ihåg sökning",
"sql_debug": "SQL felsökning",
"Create_New_Food": "Lägg till nytt livsmedel",
"Pin": "Pin",
"Pin": "Fäst",
"Edit_Food": "Redigera livsmedel",
"Move_Food": "Flytta livsmedel",
"Create_Meal_Plan_Entry": "Skapa en måltidsplan",
@@ -363,7 +363,7 @@
"ChildInheritFields_help": "Underordnade kommer att ärva dessa fält som standard.",
"InheritFields_help": "Värdena i dessa fält kommer att ärvas från förälder (Undantag: tomma shoppingkategorier ärvs inte)",
"no_pinned_recipes": "Du har inga nålade recept!",
"Pinned": "Nålad",
"Pinned": "Fäst",
"OnHand_help": "Livsmedel som finns i lager kommer inte automatiskt att läggas till på en inköpslista. Onhand-status delas med shoppinganvändare.",
"shopping_category_help": "Mataffärer kan sorteras och filtreras efter Shopping-kategori enligt gångarnas layout.",
"food_recipe_help": "Om du länkar ett recept här kommer det länkade receptet att inkluderas i alla andra recept som använder detta livsmedel",
@@ -381,11 +381,102 @@
"additional_options": "Ytterligare alternativ",
"remember_hours": "Timmar att komma ihåg",
"tree_select": "Använd trädval",
"Plural": "",
"plural_short": "",
"Use_Plural_Unit_Always": "",
"Use_Plural_Unit_Simple": "",
"Use_Plural_Food_Always": "",
"Use_Plural_Food_Simple": "",
"plural_usage_info": ""
"Plural": "Plural",
"plural_short": "plural",
"Use_Plural_Unit_Always": "Använd alltid pluralform för enhet",
"Use_Plural_Unit_Simple": "Använd pluralform för enhet dynamiskt",
"Use_Plural_Food_Always": "Använd alltid pluralform för mat",
"Use_Plural_Food_Simple": "Använd pluralform för mat dynamiskt",
"plural_usage_info": "Använd pluralformen för enheter och mat i detta utrymme.",
"Are_You_Sure": "Är du säker?",
"API": "API",
"Website": "Hemsida",
"Message": "Meddelande",
"Use_Kj": "Använd kJ istället för kcal",
"Auto_Sort_Help": "Flytta alla ingredienser till det bästa passande steget.",
"Protected": "Skyddad",
"Copy Link": "Kopiera Länk",
"Original_Text": "Original Text",
"Cosmetic": "Kosmetisk",
"import_duplicates": "För att förhindra duplicerade recept ignoreras recept med samma namn. Markera den här rutan för att importera allt.",
"Imported": "Importerad",
"Create_New_Shopping_Category": "Lägg till ny shoppingkategori",
"plan_share_desc": "Nya måltidsplaner kommer automatiskt att delas med utvalda användare.",
"Last_name": "Efternamn",
"Select_App_To_Import": "Vänligen välj en App att importera från",
"Import_Error": "Ett fel uppstod under din import. Expandera informationen längst ner på sidan för att se den.",
"Combine_All_Steps": "Kombinera alla steg i ett enda fält.",
"Ingredient Overview": "Ingrediensöversikt",
"New_Entry": "Ny post",
"one_url_per_line": "Endast en URL per rad",
"Decimals": "Decimaler",
"Default_Unit": "Standardenhet",
"Use_Fractions": "Använd bråk",
"Use_Fractions_Help": "Konvertera automatiskt decimaler till bråktal när du visar ett recept.",
"Imported_From": "Importerad från",
"Disable": "Inaktivera",
"Documentation": "Dokumentation",
"Options": "Val",
"Click_To_Edit": "Klicka för att redigera",
"paste_json": "Klistra in JSON eller HTML källkoden här för att ladda recept.",
"err_deleting_protected_resource": "Objektet du försöker radera används fortfarande och kan inte raderas.",
"Private_Recipe": "Privat Recept",
"Private_Recipe_Help": "Receptet visas bara för dig och personer som det delas med.",
"reusable_help_text": "Bör inbjudningslänken vara användbar för mer än en användare.",
"Ingredient Editor": "Ingrediensredigerare",
"warning_space_delete": "Du kan ta bort ditt utrymme inklusive alla recept, inköpslistor, måltidsplaner och allt annat du har skapat. Detta kan inte ångras! Är du säker på att du vill göra detta?",
"facet_count_info": "Visa recept antal på sökfilter.",
"food_inherit_info": "Fält på mat som ska ärvas som standard.",
"Auto_Sort": "Automatisk Sortering",
"Day": "Dag",
"Days": "Dagar",
"Hours": "Timmar",
"Instruction_Replace": "Ersätt instruktion",
"Description_Replace": "Ersätt beskrivning",
"Seconds": "Sekunder",
"Users": "Användare",
"Invites": "Inbjudningar",
"Hour": "Timme",
"Second": "Sekund",
"Manage_Emails": "Hantera mejladresser",
"Account": "Konto",
"Unpin": "Lossa",
"PinnedConfirmation": "{recipe} har fästs.",
"UnpinnedConfirmation": "{recipe} har lossats.",
"Amount": "Mängd",
"Copy Token": "Kopiera token",
"Language": "Språk",
"Theme": "Tema",
"Bookmarklet": "Bokmärke",
"Comments_setting": "Visa Kommentarer",
"no_more_images_found": "Inga ytterligare bilder hittades på webbplatsen.",
"Sticky_Nav": "Fastlåst navigering",
"Sticky_Nav_Help": "Visa alltid navigeringsmenyn högst upp på skärmen.",
"Nav_Color": "Navigeringsfärg",
"Nav_Color_Help": "Ändra navigeringsfärg.",
"click_image_import": "Klicka på bilden du vill importera till detta recept",
"reset_food_inheritance": "Återställ arv",
"reset_food_inheritance_info": "Återställ alla livsmedel till ärvda standardfält och deras överordnade värden.",
"show_ingredient_overview": "Visa en lista över alla ingredienser i början av receptet.",
"App": "App",
"Change_Password": "Ändra lösenord",
"Username": "Användarnamn",
"First_name": "Förnamn",
"Multiple": "Flera",
"Importer_Help": "Mer information och hjälp om denna import:",
"Import_Supported": "Import stöds",
"Export_Supported": "Export stöds",
"Import_Not_Yet_Supported": "Import stöds inte ännu",
"Export_Not_Yet_Supported": "Export stöds inte ännu",
"Import_Result_Info": "{imported} av totalt {total} recept blev importerat",
"Recipes_In_Import": "Recept i din importfil",
"Toggle": "Växla",
"Valid Until": "Giltig till",
"Split_All_Steps": "Dela upp alla rader i separata steg.",
"New_Supermarket": "Skapa ny mataffärs",
"New_Supermarket_Category": "Skapa ny mataffärskategori",
"Warning_Delete_Supermarket_Category": "Om du tar bort en mataffärskategori raderas också alla relationer till livsmedel. Är du säker?",
"Disabled": "Inaktiverad",
"Social_Authentication": "Social autentisering",
"Single": "Enstaka"
}

View File

@@ -1,256 +1,256 @@
{
"warning_feature_beta": "",
"err_fetching_resource": "",
"err_creating_resource": "",
"err_updating_resource": "",
"err_deleting_resource": "",
"err_deleting_protected_resource": "",
"err_moving_resource": "",
"err_merging_resource": "",
"success_fetching_resource": "",
"success_creating_resource": "",
"success_updating_resource": "",
"success_deleting_resource": "",
"success_moving_resource": "",
"success_merging_resource": "",
"file_upload_disabled": "",
"step_time_minutes": "",
"confirm_delete": "",
"import_running": "",
"all_fields_optional": "",
"convert_internal": "",
"show_only_internal": "",
"warning_feature_beta": "Ця функція зараз в БЕТІ (тестується). Будь ласка, очікуйте помилок і можливих порушень і майбутньому (можлива втрата даних), коли користуєтесь цією функцією.",
"err_fetching_resource": "Виникла помилка при отриманні ресурсу!",
"err_creating_resource": "Виникла помилка при створенні ресурсу!",
"err_updating_resource": "Виникла помилка при оновленні ресурсу!",
"err_deleting_resource": "Виникла помилка при видаленні ресурсу!",
"err_deleting_protected_resource": "Об'єкт який ви намагаєтесь видалити зараз використовується і не може бути видаленим.",
"err_moving_resource": "Виникла помилка при переміщені ресурсу!",
"err_merging_resource": "Виникла помилка при злитті ресурсу!",
"success_fetching_resource": "Успішно отримано ресурс!",
"success_creating_resource": "Успішно створено ресурс!",
"success_updating_resource": "Успішно оновлено ресурс!",
"success_deleting_resource": "Успішно видалено ресурс!",
"success_moving_resource": "Успішно переміщено ресурс!",
"success_merging_resource": "Успішно злито ресурс!",
"file_upload_disabled": "Завантаження файлів не включено на вашому просторі.",
"step_time_minutes": "Час кроку в хвилинах",
"confirm_delete": "Ви впевнені, що хочете видалити {object}?",
"import_running": "Імпортується, будь ласка зачекайте!",
"all_fields_optional": "Всі поля опціональні і можна залишити їх пустими.",
"convert_internal": "Конвертувати у внутрішній рецепт",
"show_only_internal": "Показати тільки внутрішні рецепти",
"show_split_screen": "",
"Log_Recipe_Cooking": "",
"External_Recipe_Image": "",
"Add_to_Shopping": "",
"Add_to_Plan": "",
"Step_start_time": "",
"External_Recipe_Image": "Зображення Зовнішнього Рецепту",
"Add_to_Shopping": "Додати до Покупок",
"Add_to_Plan": "Додати до Плану",
"Step_start_time": "Час початку кроку",
"Sort_by_new": "",
"Table_of_Contents": "",
"Recipes_per_page": "",
"Table_of_Contents": "Зміст",
"Recipes_per_page": "Кількість Рецептів на Сторінку",
"Show_as_header": "",
"Hide_as_header": "",
"Add_nutrition_recipe": "",
"Remove_nutrition_recipe": "",
"Add_nutrition_recipe": "Додати харчову цінність до рецепту",
"Remove_nutrition_recipe": "Видалити харчову цінність з рецепта",
"Copy_template_reference": "",
"Save_and_View": "",
"Manage_Books": "",
"Meal_Plan": "",
"Select_Book": "",
"Select_File": "",
"Recipe_Image": "",
"Import_finished": "",
"View_Recipes": "",
"Save_and_View": "Зберегти і Подивитися",
"Manage_Books": "Управління Книжкою",
"Meal_Plan": "План Харчування",
"Select_Book": "Вибрати Книжку",
"Select_File": "Вибрати Файл",
"Recipe_Image": "Зображення Рецепту",
"Import_finished": "Імпорт закінчено",
"View_Recipes": "Подивитися Рецепт",
"Log_Cooking": "",
"New_Recipe": "",
"Url_Import": "",
"Reset_Search": "",
"Recently_Viewed": "",
"Load_More": "",
"New_Keyword": "",
"Delete_Keyword": "",
"Edit_Keyword": "",
"Edit_Recipe": "",
"Move_Keyword": "",
"Merge_Keyword": "",
"Hide_Keywords": "",
"Hide_Recipes": "",
"Move_Up": "",
"Move_Down": "",
"Step_Name": "",
"Step_Type": "",
"New_Recipe": "Новий Рецепт",
"Url_Import": "Імпорт за посиланням",
"Reset_Search": "Скинути Пошук",
"Recently_Viewed": "Нещодавно переглянуті",
"Load_More": "Завантажити більше",
"New_Keyword": "Нові Ключові слова",
"Delete_Keyword": "Видалити Ключове слово",
"Edit_Keyword": "Редагувати Ключове слово",
"Edit_Recipe": "Редагувати Рецепт",
"Move_Keyword": "Перемістити Ключове слово",
"Merge_Keyword": "Об'єднати Ключове слово",
"Hide_Keywords": "Сховати Ключове слово",
"Hide_Recipes": "Сховати Рецепти",
"Move_Up": "Перемістити уверх",
"Move_Down": "Перемістити вниз",
"Step_Name": "Ім'я Кроку",
"Step_Type": "Тип Кроку",
"Make_Header": "",
"Make_Ingredient": "",
"Enable_Amount": "",
"Disable_Amount": "",
"Ingredient Editor": "",
"Add_Step": "",
"Keywords": "",
"Books": "",
"Proteins": "",
"Fats": "",
"Carbohydrates": "",
"Calories": "",
"Energy": "",
"Nutrition": "",
"Date": "",
"Share": "",
"Automation": "",
"Parameter": "",
"Export": "",
"Copy": "",
"Rating": "",
"Close": "",
"Cancel": "",
"Link": "",
"Add": "",
"New": "",
"Note": "",
"Success": "",
"Failure": "",
"Protected": "",
"Ingredients": "",
"Supermarket": "",
"Categories": "",
"Category": "",
"Selected": "",
"min": "",
"Servings": "",
"Waiting": "",
"Preparation": "",
"External": "",
"Size": "",
"Files": "",
"File": "",
"Edit": "",
"Image": "",
"Delete": "",
"Open": "",
"Ok": "",
"Save": "",
"Step": "",
"Search": "",
"Import": "",
"Print": "",
"Settings": "",
"or": "",
"and": "",
"Information": "",
"Download": "",
"Create": "",
"Search Settings": "",
"Enable_Amount": "Включити Кількість",
"Disable_Amount": "Виключити Кількість",
"Ingredient Editor": "Редактор Інгредієнтів",
"Add_Step": "Додати Крок",
"Keywords": "Ключові слова",
"Books": "Книжки",
"Proteins": "Білки",
"Fats": "Жири",
"Carbohydrates": "Вуглеводи",
"Calories": "Калорії",
"Energy": "Енергія",
"Nutrition": "Харчова цінність",
"Date": "Дата",
"Share": "Поділитися",
"Automation": "Автоматизація",
"Parameter": "Параметр",
"Export": "Експорт",
"Copy": "Копіювати",
"Rating": "Рейтинг",
"Close": "Закрити",
"Cancel": "Відмінити",
"Link": "Посилання",
"Add": "Додати",
"New": "Новий",
"Note": "Нотатка",
"Success": "Успішно",
"Failure": "Невдало",
"Protected": "Захищено",
"Ingredients": "Інгредієнти",
"Supermarket": "Супермаркет",
"Categories": "Категорії",
"Category": "Категорія",
"Selected": "Вибрано",
"min": "хв",
"Servings": "Порції",
"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": "",
"delete_confirmation": "",
"move_confirmation": "",
"merge_confirmation": "",
"create_rule": "",
"Recipes": "Рецепти",
"Move": "Перемістити",
"Merge": "Об'єднати",
"Parent": "Батько",
"delete_confirmation": "Ви впевнені, що хочете видалити {source}?",
"move_confirmation": "Перемістити <i>{child}</i> до батька <i>{parent}</i>",
"merge_confirmation": "Замінити <i>{source}</i> на <i>{target}</i>",
"create_rule": "і створити автоматизацію",
"move_selection": "",
"merge_selection": "",
"Root": "",
"Ignore_Shopping": "",
"Shopping_Category": "",
"Shopping_Categories": "",
"Edit_Food": "",
"Move_Food": "",
"New_Food": "",
"Hide_Food": "",
"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": "",
"Recipe_Book": "",
"del_confirmation_tree": "",
"delete_title": "",
"create_title": "",
"edit_title": "",
"Name": "",
"Type": "",
"Description": "",
"Recipe": "",
"tree_root": "",
"Icon": "",
"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": "",
"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": "",
"AddFoodToShopping": "",
"RemoveFoodFromShopping": "",
"DeleteShoppingConfirm": "",
"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": "",
"Inherit": "",
"InheritFields": "",
"FoodInherit": "",
"ShowUncategorizedFood": "",
"GroupBy": "",
"SupermarketCategoriesOnly": "",
"MoveCategory": "",
"CountMore": "",
"IgnoreThis": "",
"DelayFor": "",
"Warning": "",
"NoCategory": "",
"Delete_Food": "Видалити Їжу",
"No_ID": "ID не знайдено, неможливо видалити.",
"Meal_Plan_Days": "Майбутній план харчування",
"merge_title": "Об'єднати {type}",
"move_title": "Перемістити {type}",
"Food": "Їжа",
"Recipe_Book": "Книга Рецептів",
"del_confirmation_tree": "Ви впевненні, що хочете видалити {source} і всіх його дітей?",
"delete_title": "Видалити {type}",
"create_title": "Новий {type}",
"edit_title": "Редагувати {type}",
"Name": "Ім'я",
"Type": "Тип",
"Description": "Опис",
"Recipe": "Рецепт",
"tree_root": "Корінь Дерева",
"Icon": "Іконка",
"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": "Ctrl",
"Key_Shift": "Shift",
"Time": "Час",
"Text": "Текст",
"Shopping_list": "Список Покупок",
"Added_by": "Додано",
"Added_on": "Додано На",
"AddToShopping": "Додати до списку покупок",
"IngredientInShopping": "Цей інгредієнт є в вашому списку покупок.",
"NotInShopping": "{food} немає в вашому списку покупок.",
"OnHand": "Зараз На Руках",
"FoodOnHand": "Ви маєте {food} на руках.",
"FoodNotOnHand": "У вас немає {food} на руках.",
"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": "Новий Тип страви",
"AddFoodToShopping": "Додати {food} до вашого списку покупок",
"RemoveFoodFromShopping": "Видалити {food} з вашого списку покупок",
"DeleteShoppingConfirm": "Ви впевнені, що хочете видалити {food} з вашого списку покупок?",
"IgnoredFood": "{food} ігнорується в покупках.",
"Add_Servings_to_Shopping": "Додати {servings} Порції до Покупок",
"Week_Numbers": "Номер тижня",
"Show_Week_Numbers": "Показати номер тижня?",
"Export_As_ICal": "Експортувати теперішній період до формату iCal",
"Export_To_ICal": "Експортувати .ics",
"Cannot_Add_Notes_To_Shopping": "Нотатки не можуть бути доданими до списку покупок",
"Added_To_Shopping_List": "Додано до списку покупок",
"Shopping_List_Empty": "Ваш список покупок зараз пустий, ви можете додати товари за допомогою контекстного меню плану харчування (права кнопка мишки на картку або на ліву кнопку на іконку меню)",
"Next_Period": "Наступний період",
"Previous_Period": "Попередній Період",
"Current_Period": "Теперішній Період",
"Next_Day": "Наступний День",
"Previous_Day": "Попередній День",
"Inherit": "Успадкувати",
"InheritFields": "Успадкувати Значення Полів",
"FoodInherit": "Пола Успадкованої Їжі",
"ShowUncategorizedFood": "Показати Невідомо",
"GroupBy": "По Групі",
"SupermarketCategoriesOnly": "Тільки Категорії Супермаркету",
"MoveCategory": "Перемістити До: ",
"CountMore": "...+{count} більше",
"IgnoreThis": "Ніколи {food} автоматично не додавати до покупок",
"DelayFor": "Затримка на {hours} годин",
"Warning": "Увага",
"NoCategory": "Жодна категорія не вибрана.",
"InheritWarning": "",
"ShowDelayed": "",
"Completed": "",
"OfflineAlert": "",
"shopping_share": "",
"shopping_auto_sync": "",
"one_url_per_line": "",
"mealplan_autoadd_shopping": "",
"ShowDelayed": "Показати Відкладені Предмети",
"Completed": "Виконано",
"OfflineAlert": "Ви офлайн, список покупок може не синхронізуватися.",
"shopping_share": "Поділитися Списком Покупок",
"shopping_auto_sync": "Автосинхронізація",
"one_url_per_line": "Одна URL на лінію",
"mealplan_autoadd_shopping": "Автоматично Додати План Харчування",
"mealplan_autoexclude_onhand": "",
"mealplan_autoinclude_related": "",
"mealplan_autoinclude_related": "Додати Пов'язані Рецепти",
"default_delay": "",
"shopping_share_desc": "",
"shopping_share_desc": "Користувачі будуть бачати всі елементи, які ви додаєте до списку покупок. Вони мають додати вас, щоб бачати елементи в їх списках.",
"shopping_auto_sync_desc": "",
"mealplan_autoadd_shopping_desc": "",
"mealplan_autoexclude_onhand_desc": "",
@@ -419,5 +419,24 @@
"Use_Plural_Unit_Simple": "",
"Use_Plural_Food_Always": "",
"Use_Plural_Food_Simple": "",
"plural_usage_info": ""
"plural_usage_info": "",
"warning_space_delete": "Ви можете видалити ваш простір разом зі всіма рецептами, списками покупок, планами харчування і всім іншим, що ви створили. Ця дія незворотня! Ви впевнені, що бажаєте це зробити?",
"facet_count_info": "Показати кількість рецептів на полі пошуку.",
"Amount": "Кількість",
"Auto_Sort": "Автоматичне сортування",
"Auto_Sort_Help": "Перемістити всі інгредієнти до більш підходящого кроку.",
"reusable_help_text": "Запрошувальне посилання має бути тільки для одного користувача.",
"Copy Token": "Скопіювати Токен",
"Decimals": "Десятки",
"Language": "Мова",
"Theme": "Тема",
"Private_Recipe": "Приватний Рецепт",
"Private_Recipe_Help": "Рецепт показаний тільки Вам і тими з ким ви поділилися їм.",
"Description_Replace": "Замінити Опис",
"Instruction_Replace": "Замінити Інструкцію",
"Use_Fractions": "Використовувати дроби",
"Use_Fractions_Help": "Автоматично конвертувати десятки в дроби, коли дивитесь рецепт.",
"Copy Link": "Скопіювати Посилання",
"Original_Text": "Оригінальний текст",
"Default_Unit": "Одиниця замовчуванням"
}

View File

@@ -66,7 +66,7 @@
"Cancel": "取消",
"Delete": "删除",
"Open": "打开",
"Ok": "打开",
"Ok": "确认",
"Save": "保存",
"Step": "步骤",
"Search": "搜索",
@@ -477,5 +477,7 @@
"UnpinnedConfirmation": "{recipe} 已取消固定。",
"Unpin": "取消固定",
"Auto_Sort": "自动分类",
"Auto_Sort_Help": "将所有食材移动到最恰当的步骤。"
"Auto_Sort_Help": "将所有食材移动到最恰当的步骤。",
"Create Recipe": "创建食谱",
"Import Recipe": "导入食谱"
}

View File

@@ -0,0 +1,33 @@
https://pinia.vuejs.org/core-concepts/plugins.html#adding-new-state
export function BaseStorePlugin () {
return {
collection: [],
item: {},
getCollection: function (url) {
api.get(url)
.then((response) => {
this.collection = response.data;
})
.catch((error) => {
this.handleError(error);
});
},
getItem: function (url) {
api.get(url)
.then((response) => {
this.item = response.data;
})
.catch((error) => {
this.handleError(error);
});
},
handleError: function (error) {
window.alert(error);
},
};
}

View File

@@ -0,0 +1,89 @@
import {defineStore} from 'pinia'
import {ApiApiFactory} from "@/utils/openapi/api";
const _STORE_ID = 'meal_plan_store'
import Vue from "vue"
import {StandardToasts} from "@/utils/utils";
/*
* test store to play around with pinia and see if it can work for my usecases
* dont trust that all mealplans are in store as there is no cache validation logic, its just a shared data holder
* */
export const useMealPlanStore = defineStore(_STORE_ID, {
state: () => ({
plans: {},
currently_updating: null,
}),
getters: {
plan_list: function () {
let plan_list = []
for (let key in this.plans) {
plan_list.push(this.plans[key]);
}
return plan_list
},
empty_meal_plan: function () {
return {
date: null,
id: -1,
meal_type: null,
note: "",
note_markdown: "",
recipe: null,
servings: 1,
shared: [],
title: "",
title_placeholder: 'Title', // meal plan edit modal should be improved to not need this
}
}
},
actions: {
refreshFromAPI(from_date, to_date) {
if (this.currently_updating !== [from_date, to_date]) {
this.currently_updating = [from_date, to_date] // certainly no perfect check but better than nothing
let options = {
query: {
from_date: from_date,
to_date: to_date,
},
}
let apiClient = new ApiApiFactory()
apiClient.listMealPlans(options).then(r => {
r.data.forEach((p) => {
Vue.set(this.plans, p.id, p)
})
this.currently_updating = null
})
}
},
createObject(object) {
let apiClient = new ApiApiFactory()
return apiClient.createMealPlan(object).then(r => {
//StandardToasts.makeStandardToast(this, StandardToasts.SUCCESS_CREATE)
Vue.set(this.plans, r.data.id, r.data)
return r
}).catch(err => {
StandardToasts.makeStandardToast(this, StandardToasts.FAIL_CREATE, err)
})
},
updateObject(object) {
let apiClient = new ApiApiFactory()
return apiClient.updateMealPlan(object.id, object).then(r => {
//StandardToasts.makeStandardToast(this, StandardToasts.SUCCESS_UPDATE)
Vue.set(this.plans, object.id, object)
}).catch(err => {
StandardToasts.makeStandardToast(this, StandardToasts.FAIL_UPDATE, err)
})
},
deleteObject(object) {
let apiClient = new ApiApiFactory()
return apiClient.destroyMealPlan(object.id).then(r => {
//StandardToasts.makeStandardToast(this, StandardToasts.SUCCESS_DELETE)
Vue.delete(this.plans, object.id)
}).catch(err => {
StandardToasts.makeStandardToast(this, StandardToasts.FAIL_DELETE, err)
})
}
},
})

View File

@@ -0,0 +1,85 @@
import {defineStore} from 'pinia'
import {ApiApiFactory} from "@/utils/openapi/api";
const _STALE_TIME_IN_MS = 1000 * 30
const _STORE_ID = 'user_preference_store'
export const useUserPreferenceStore = defineStore(_STORE_ID, {
state: () => ({
data: null,
updated_at: null,
currently_updating: false,
}),
getters: {
},
actions: {
/**
* gets data from the store either directly or refreshes from API if data is considered stale
* @returns {UserPreference|*|Promise<axios.AxiosResponse<UserPreference>>}
*/
getData: function () {
if (this.isStaleOrEmpty) {
return this.refreshFromAPI()
} else {
return this.data
}
},
/**
* get data from store. Does not use API, if store is not initialized returns null.
* @returns {null|UserPreference|*}
*/
getStaleData: function () {
return this.data
},
/**
* checks if update timestamp is older than configured stale time interval
* @returns {boolean} true if data is considered stale and should be updated
*/
isStale() {
return this.updated_at === null || ((new Date()) - this.updated_at) > _STALE_TIME_IN_MS;
},
/**
* checks if data of store is empty/not initialized
* @returns {boolean} true if store is empty
*/
isEmpty() {
return this.data === null
},
/**
* checks if store is empty or data is considered stale, see isStale() and isEmpty()
* @returns {boolean}
*/
isStaleOrEmpty() {
return this.isStale() || this.isEmpty()
},
/**
* refreshes store data if isStaleOrEmpty() is true
* @returns {Promise<axios.AxiosResponse<UserPreference>>} returns promise with data
*/
updateIfStaleOrEmpty() {
if (this.isStaleOrEmpty) {
return this.refreshFromAPI()
}
},
/**
* refreshes store data from API
* @returns {Promise<axios.AxiosResponse<UserPreference>>} returns promise with data
*/
refreshFromAPI() {
let apiClient = new ApiApiFactory()
if(!this.currently_updating){
this.currently_updating = true
return apiClient.retrieveUserPreference(localStorage.getItem('USER_ID')).then(r => {
this.data = r.data
this.updated_at = new Date()
this.currently_updating = false
return this.data
}).catch(err => {
this.currently_updating = false
})
}
},
},
})

0
vue/src/stores/root.js Normal file
View File

View File

@@ -1,8 +1,9 @@
// These JavaScript module imports need to be bundled:
import {precacheAndRoute} from 'workbox-precaching';
import {registerRoute, setCatchHandler} from 'workbox-routing';
import {CacheFirst, NetworkFirst, StaleWhileRevalidate} from 'workbox-strategies';
import {CacheFirst, NetworkFirst, NetworkOnly, StaleWhileRevalidate} from 'workbox-strategies';
import {ExpirationPlugin} from 'workbox-expiration';
import {BackgroundSyncPlugin, Queue} from "workbox-background-sync";
const OFFLINE_CACHE_NAME = 'offline-html';
@@ -77,6 +78,39 @@ registerRoute(
})
)
const queue = new Queue('shopping-sync-queue', {
maxRetentionTime: 7 * 24 * 60,
});
registerRoute(
new RegExp('api/shopping-list-entry/([0-9]+)'),
new NetworkOnly({
plugins: [
{
fetchDidFail: async ({request}) => {
await queue.pushRequest({request});
},
}
],
}),
'PATCH'
)
addEventListener('message', (event) => {
if (event.data.type === 'BGSYNC_REPLAY_REQUESTS') {
queue.replayRequests().then((r) => {
event.ports[0].postMessage('REPLAY_SUCCESS SW');
}).catch((err) => {
event.ports[0].postMessage('REPLAY_FAILURE');
});
}
if (event.data.type === 'BGSYNC_COUNT_QUEUE') {
queue.getAll().then((r) => {
event.ports[0].postMessage(r.length);
})
}
});
registerRoute(
new RegExp('api/*'),
new NetworkFirst({

View File

@@ -359,6 +359,7 @@ export const ApiMixin = {
}
},
methods: {
// if passing parameters that are not part of the offical schema of the endpoint use parameter: options: {query: {simple: 1}}
genericAPI: function (model, action, options) {
let setup = getConfig(model, action)
if (setup?.config?.function) {

View File

@@ -158,9 +158,9 @@
"@babel/highlight" "^7.18.6"
"@babel/compat-data@^7.17.7", "@babel/compat-data@^7.20.1", "@babel/compat-data@^7.20.5":
version "7.20.10"
resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.20.10.tgz#9d92fa81b87542fff50e848ed585b4212c1d34ec"
integrity sha512-sEnuDPpOJR/fcafHMjpcpGN5M2jbUGUHwmuWKM/YdPzeEDJg8bgmbcWQFUfE32MQjti1koACvoPVsDe8Uq+idg==
version "7.20.14"
resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.20.14.tgz#4106fc8b755f3e3ee0a0a7c27dde5de1d2b2baf8"
integrity sha512-0YpKHD6ImkWMEINCyDAD0HLLUH/lPCefG8ld9it8DJB2wnApraKuhgYTvTY1z7UFIfBTGy5LwncZ+5HWWGbhFw==
"@babel/core@^7.1.6", "@babel/core@^7.10.3", "@babel/core@^7.11.1", "@babel/core@^7.12.16", "@babel/core@^7.8.4":
version "7.20.12"
@@ -193,9 +193,9 @@
semver "^6.3.0"
"@babel/generator@^7.20.7":
version "7.20.7"
resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.20.7.tgz#f8ef57c8242665c5929fe2e8d82ba75460187b4a"
integrity sha512-7wqMOJq8doJMZmP4ApXTzLxSr7+oO2jroJURrVEp6XShrQUObV8Tq/D0NCcoYg2uHqUrjzO0zwBjoYzelxK+sw==
version "7.20.14"
resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.20.14.tgz#9fa772c9f86a46c6ac9b321039400712b96f64ce"
integrity sha512-AEmuXHdcD3A52HHXxaTmYlb8q/xMEhoRP67B3T4Oq7lbmSoqroMZzjnGj3+i1io3pdnF8iBYVu4Ilj+c4hBxYg==
dependencies:
"@babel/types" "^7.20.7"
"@jridgewell/gen-mapping" "^0.3.2"
@@ -415,9 +415,9 @@
js-tokens "^4.0.0"
"@babel/parser@^7.1.6", "@babel/parser@^7.16.4", "@babel/parser@^7.18.4", "@babel/parser@^7.20.13", "@babel/parser@^7.20.7", "@babel/parser@^7.7.0":
version "7.20.13"
resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.20.13.tgz#ddf1eb5a813588d2fb1692b70c6fce75b945c088"
integrity sha512-gFDLKMfpiXCsjt4za2JA9oTMn70CeseCehb11kRZgvd7+F67Hih3OHOK24cRrWECJ/ljfPGac6ygXAs/C8kIvw==
version "7.20.15"
resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.20.15.tgz#eec9f36d8eaf0948bb88c87a46784b5ee9fd0c89"
integrity sha512-DI4a1oZuf8wC+oAJA9RW6ga3Zbe8RZFt7kD9i4qAspz3I/yHet1VvC3DiSy/fsUvv5pvJuNPh0LPOdCcqinDPg==
"@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@^7.18.6":
version "7.18.6"
@@ -732,9 +732,9 @@
"@babel/helper-plugin-utils" "^7.18.6"
"@babel/plugin-transform-block-scoping@^7.20.2":
version "7.20.11"
resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.20.11.tgz#9f5a3424bd112a3f32fe0cf9364fbb155cff262a"
integrity sha512-tA4N427a7fjf1P0/2I4ScsHGc5jcHPbb30xMbaTke2gxDuWpUfXDuX1FEymJwKk4tuGUvGcejAR6HdZVqmmPyw==
version "7.20.15"
resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.20.15.tgz#3e1b2aa9cbbe1eb8d644c823141a9c5c2a22392d"
integrity sha512-Vv4DMZ6MiNOhu/LdaZsT/bsLRxgL94d269Mv4R/9sp6+Mp++X/JqypZYypJXLlM4mlL352/Egzbzr98iABH1CA==
dependencies:
"@babel/helper-plugin-utils" "^7.20.2"
@@ -1109,6 +1109,11 @@
pirates "^4.0.5"
source-map-support "^0.5.16"
"@babel/regjsgen@^0.8.0":
version "0.8.0"
resolved "https://registry.yarnpkg.com/@babel/regjsgen/-/regjsgen-0.8.0.tgz#f0ba69b075e1f05fb2825b7fad991e7adbb18310"
integrity sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA==
"@babel/runtime@^7.11.2", "@babel/runtime@^7.12.13", "@babel/runtime@^7.12.5", "@babel/runtime@^7.14.0", "@babel/runtime@^7.18.6", "@babel/runtime@^7.3.1", "@babel/runtime@^7.5.5", "@babel/runtime@^7.8.4":
version "7.20.13"
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.20.13.tgz#7055ab8a7cff2b8f6058bf6ae45ff84ad2aded4b"
@@ -1178,31 +1183,31 @@
"@graphql-tools/utils" "8.9.0"
tslib "^2.4.0"
"@graphql-tools/merge@8.3.15":
version "8.3.15"
resolved "https://registry.yarnpkg.com/@graphql-tools/merge/-/merge-8.3.15.tgz#9b24ee5e9c36074684515c7d1587cd3e200c8a8f"
integrity sha512-hYYOlsqkUlL6oOo7zzuk6hIv7xQzy+x21sgK84d5FWaiWYkLYh9As8myuDd9SD5xovWWQ9m/iRhIOVDEMSyEKA==
"@graphql-tools/merge@8.3.18":
version "8.3.18"
resolved "https://registry.yarnpkg.com/@graphql-tools/merge/-/merge-8.3.18.tgz#bfbb517c68598a885809f16ce5c3bb1ebb8f04a2"
integrity sha512-R8nBglvRWPAyLpZL/f3lxsY7wjnAeE0l056zHhcO/CgpvK76KYUt9oEkR05i8Hmt8DLRycBN0FiotJ0yDQWTVA==
dependencies:
"@graphql-tools/utils" "9.1.4"
"@graphql-tools/utils" "9.2.1"
tslib "^2.4.0"
"@graphql-tools/mock@^8.1.2":
version "8.7.15"
resolved "https://registry.yarnpkg.com/@graphql-tools/mock/-/mock-8.7.15.tgz#057714064ea99340bf89e95b5595b1921d406495"
integrity sha512-0zImG5tuObhowqtijlB6TMAIVtCIBsnGGwNW8gnCOa+xZAqfGdUMsSma17tHC2XuI7xhv7A0O8pika9e3APLUg==
version "8.7.18"
resolved "https://registry.yarnpkg.com/@graphql-tools/mock/-/mock-8.7.18.tgz#12a3eee55e406197b81dca570d062918db206b2e"
integrity sha512-ZbXMp86V0DmfgUZhr5aGHtNIS2hBazhvTpPlFCyNOP+RMio3ErKnSsma3T1jV1ZyMo11l7QrxV9Xxn3uA0dv+w==
dependencies:
"@graphql-tools/schema" "9.0.13"
"@graphql-tools/utils" "9.1.4"
"@graphql-tools/schema" "9.0.16"
"@graphql-tools/utils" "9.2.1"
fast-json-stable-stringify "^2.1.0"
tslib "^2.4.0"
"@graphql-tools/schema@9.0.13":
version "9.0.13"
resolved "https://registry.yarnpkg.com/@graphql-tools/schema/-/schema-9.0.13.tgz#56b994777df29ac36586a3200fb6397abf7b9d83"
integrity sha512-guRA3fwAtv+M1Kh930P4ydH9aKJTWscIkhVFcWpj/cnjYYxj88jkEJ15ZNiJX/2breNY+sbVgmlgLKb6aXi/Jg==
"@graphql-tools/schema@9.0.16":
version "9.0.16"
resolved "https://registry.yarnpkg.com/@graphql-tools/schema/-/schema-9.0.16.tgz#7d340d69e6094dc01a2b9e625c7bb4fff89ea521"
integrity sha512-kF+tbYPPf/6K2aHG3e1SWIbapDLQaqnIHVRG6ow3onkFoowwtKszvUyOASL6Krcv2x9bIMvd1UkvRf9OaoROQQ==
dependencies:
"@graphql-tools/merge" "8.3.15"
"@graphql-tools/utils" "9.1.4"
"@graphql-tools/merge" "8.3.18"
"@graphql-tools/utils" "9.2.1"
tslib "^2.4.0"
value-or-promise "1.0.12"
@@ -1223,13 +1228,19 @@
dependencies:
tslib "^2.4.0"
"@graphql-tools/utils@9.1.4":
version "9.1.4"
resolved "https://registry.yarnpkg.com/@graphql-tools/utils/-/utils-9.1.4.tgz#2c9e0aefc9655dd73247667befe3c850ec014f3f"
integrity sha512-hgIeLt95h9nQgQuzbbdhuZmh+8WV7RZ/6GbTj6t3IU4Zd2zs9yYJ2jgW/krO587GMOY8zCwrjNOMzD40u3l7Vg==
"@graphql-tools/utils@9.2.1":
version "9.2.1"
resolved "https://registry.yarnpkg.com/@graphql-tools/utils/-/utils-9.2.1.tgz#1b3df0ef166cfa3eae706e3518b17d5922721c57"
integrity sha512-WUw506Ql6xzmOORlriNrD6Ugx+HjVgYxt9KCXD9mHAak+eaXSwuGGPyE60hy9xaDEoXKBsG7SkG69ybitaVl6A==
dependencies:
"@graphql-typed-document-node/core" "^3.1.1"
tslib "^2.4.0"
"@graphql-typed-document-node/core@^3.1.1":
version "3.1.1"
resolved "https://registry.yarnpkg.com/@graphql-typed-document-node/core/-/core-3.1.1.tgz#076d78ce99822258cf813ecc1e7fa460fa74d052"
integrity sha512-NQ17ii0rK1b34VZonlmT2QMJFI70m0TRwbknO/ihlbatXyaktDhN/98vBiUU6kNBPljqGqyIrl2T4nY2RpFANg==
"@hapi/address@2.x.x":
version "2.1.4"
resolved "https://registry.yarnpkg.com/@hapi/address/-/address-2.1.4.tgz#5d67ed43f3fd41a69d4b9ff7b56e7c0d1d0a81e5"
@@ -1639,9 +1650,9 @@
"@types/estree" "*"
"@types/eslint@*", "@types/eslint@^7.29.0 || ^8.4.1":
version "8.4.10"
resolved "https://registry.yarnpkg.com/@types/eslint/-/eslint-8.4.10.tgz#19731b9685c19ed1552da7052b6f668ed7eb64bb"
integrity sha512-Sl/HOqN8NKPmhWo2VBEPm0nvHnu2LL3v9vKo8MEq0EtbJ4eVzGPl41VNPvn5E1i5poMk4/XD8UriLHpJvEP/Nw==
version "8.21.0"
resolved "https://registry.yarnpkg.com/@types/eslint/-/eslint-8.21.0.tgz#21724cfe12b96696feafab05829695d4d7bd7c48"
integrity sha512-35EhHNOXgxnUgh4XCJsGhE7zdlDhYDN/aMG6UbkByCFFNgQ7b3U+uVoqBpicFydR8JEfgdjCF7SJ7MiJfzuiTA==
dependencies:
"@types/estree" "*"
"@types/json-schema" "*"
@@ -1661,10 +1672,10 @@
resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.51.tgz#cfd70924a25a3fd32b218e5e420e6897e1ac4f40"
integrity sha512-CuPgU6f3eT/XgKKPqKd/gLZV1Xmvf1a2R5POBOGQa6uv82xpls89HU5zKeVoyR8XzHd1RGNOlQlvUe3CFkjWNQ==
"@types/express-serve-static-core@*", "@types/express-serve-static-core@^4.17.18", "@types/express-serve-static-core@^4.17.31":
version "4.17.32"
resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.17.32.tgz#93dda387f5516af616d8d3f05f2c4c79d81e1b82"
integrity sha512-aI5h/VOkxOF2Z1saPy0Zsxs5avets/iaiAJYznQFm5By/pamU31xWKL//epiF4OfUA2qTOc9PV6tCUjhO8wlZA==
"@types/express-serve-static-core@*", "@types/express-serve-static-core@^4.17.18", "@types/express-serve-static-core@^4.17.33":
version "4.17.33"
resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.17.33.tgz#de35d30a9d637dc1450ad18dd583d75d5733d543"
integrity sha512-TPBqmR/HRYI3eC2E5hmiivIzv+bidAfXofM+sbonAGvyDhySGw9/PQZFt2BLOrjUUR++4eJVpx6KnLQK1Fk9tA==
dependencies:
"@types/node" "*"
"@types/qs" "*"
@@ -1680,12 +1691,12 @@
"@types/range-parser" "*"
"@types/express@*", "@types/express@^4.17.13":
version "4.17.15"
resolved "https://registry.yarnpkg.com/@types/express/-/express-4.17.15.tgz#9290e983ec8b054b65a5abccb610411953d417ff"
integrity sha512-Yv0k4bXGOH+8a+7bELd2PqHQsuiANB+A8a4gnQrkRWzrkKlb6KHaVvyXhqs04sVW/OWlbPyYxRgYlIXLfrufMQ==
version "4.17.17"
resolved "https://registry.yarnpkg.com/@types/express/-/express-4.17.17.tgz#01d5437f6ef9cfa8668e616e13c2f2ac9a491ae4"
integrity sha512-Q4FmmuLGBG58btUnfS1c1r/NQdlp3DMfGDGig8WhfpA2YRUtEkxAjkZb0yvplJGYdF1fsQ81iMDcH24sSCNC/Q==
dependencies:
"@types/body-parser" "*"
"@types/express-serve-static-core" "^4.17.31"
"@types/express-serve-static-core" "^4.17.33"
"@types/qs" "*"
"@types/serve-static" "*"
@@ -1747,9 +1758,9 @@
integrity sha512-jhuKLIRrhvCPLqwPcx6INqmKeiA5EWrsCOPhrlFSrbrmU4ZMPjj5Ul/oLCMDO98XRUIwVm78xICz4EPCektzeQ==
"@types/node@*":
version "18.11.18"
resolved "https://registry.yarnpkg.com/@types/node/-/node-18.11.18.tgz#8dfb97f0da23c2293e554c5a50d61ef134d7697f"
integrity sha512-DHQpWGjyQKSHj3ebjFI/wRKcqQcdR+MoFBygntYOZytCqNfkd2ZC4ARDJ2DQqhjH5p85Nnd3jhUJIXrszFX/JA==
version "18.13.0"
resolved "https://registry.yarnpkg.com/@types/node/-/node-18.13.0.tgz#0400d1e6ce87e9d3032c19eb6c58205b0d3f7850"
integrity sha512-gC3TazRzGoOnoKAhUx+Q0t8S9Tzs74z7m0ipwGpSqQrleP14hKxP4/JUeEQcD3W1/aIpnWl8pHowI7WokuZpXg==
"@types/node@^10.1.0":
version "10.17.60"
@@ -1871,14 +1882,15 @@
tsutils "^3.21.0"
"@typescript-eslint/eslint-plugin@^5.0.0":
version "5.48.2"
resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.48.2.tgz#112e6ae1e23a1dc8333ce82bb9c65c2608b4d8a3"
integrity sha512-sR0Gja9Ky1teIq4qJOl0nC+Tk64/uYdX+mi+5iB//MH8gwyx8e3SOyhEzeLZEFEEfCaLf8KJq+Bd/6je1t+CAg==
version "5.51.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.51.0.tgz#da3f2819633061ced84bb82c53bba45a6fe9963a"
integrity sha512-wcAwhEWm1RgNd7dxD/o+nnLW8oH+6RK1OGnmbmkj/GGoDPV1WWMVP0FXYQBivKHdwM1pwii3bt//RC62EriIUQ==
dependencies:
"@typescript-eslint/scope-manager" "5.48.2"
"@typescript-eslint/type-utils" "5.48.2"
"@typescript-eslint/utils" "5.48.2"
"@typescript-eslint/scope-manager" "5.51.0"
"@typescript-eslint/type-utils" "5.51.0"
"@typescript-eslint/utils" "5.51.0"
debug "^4.3.4"
grapheme-splitter "^1.0.4"
ignore "^5.2.0"
natural-compare-lite "^1.4.0"
regexpp "^3.2.0"
@@ -1898,13 +1910,13 @@
eslint-utils "^3.0.0"
"@typescript-eslint/parser@^5.0.0", "@typescript-eslint/parser@^5.47.1":
version "5.48.2"
resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.48.2.tgz#c9edef2a0922d26a37dba03be20c5fff378313b3"
integrity sha512-38zMsKsG2sIuM5Oi/olurGwYJXzmtdsHhn5mI/pQogP+BjYVkK5iRazCQ8RGS0V+YLk282uWElN70zAAUmaYHw==
version "5.51.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.51.0.tgz#2d74626652096d966ef107f44b9479f02f51f271"
integrity sha512-fEV0R9gGmfpDeRzJXn+fGQKcl0inIeYobmmUWijZh9zA7bxJ8clPhV9up2ZQzATxAiFAECqPQyMDB4o4B81AaA==
dependencies:
"@typescript-eslint/scope-manager" "5.48.2"
"@typescript-eslint/types" "5.48.2"
"@typescript-eslint/typescript-estree" "5.48.2"
"@typescript-eslint/scope-manager" "5.51.0"
"@typescript-eslint/types" "5.51.0"
"@typescript-eslint/typescript-estree" "5.51.0"
debug "^4.3.4"
"@typescript-eslint/scope-manager@4.33.0":
@@ -1915,21 +1927,21 @@
"@typescript-eslint/types" "4.33.0"
"@typescript-eslint/visitor-keys" "4.33.0"
"@typescript-eslint/scope-manager@5.48.2":
version "5.48.2"
resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.48.2.tgz#bb7676cb78f1e94921eaab637a4b5d596f838abc"
integrity sha512-zEUFfonQid5KRDKoI3O+uP1GnrFd4tIHlvs+sTJXiWuypUWMuDaottkJuR612wQfOkjYbsaskSIURV9xo4f+Fw==
"@typescript-eslint/scope-manager@5.51.0":
version "5.51.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.51.0.tgz#ad3e3c2ecf762d9a4196c0fbfe19b142ac498990"
integrity sha512-gNpxRdlx5qw3yaHA0SFuTjW4rxeYhpHxt491PEcKF8Z6zpq0kMhe0Tolxt0qjlojS+/wArSDlj/LtE69xUJphQ==
dependencies:
"@typescript-eslint/types" "5.48.2"
"@typescript-eslint/visitor-keys" "5.48.2"
"@typescript-eslint/types" "5.51.0"
"@typescript-eslint/visitor-keys" "5.51.0"
"@typescript-eslint/type-utils@5.48.2":
version "5.48.2"
resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-5.48.2.tgz#7d3aeca9fa37a7ab7e3d9056a99b42f342c48ad7"
integrity sha512-QVWx7J5sPMRiOMJp5dYshPxABRoZV1xbRirqSk8yuIIsu0nvMTZesKErEA3Oix1k+uvsk8Cs8TGJ6kQ0ndAcew==
"@typescript-eslint/type-utils@5.51.0":
version "5.51.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-5.51.0.tgz#7af48005531700b62a20963501d47dfb27095988"
integrity sha512-QHC5KKyfV8sNSyHqfNa0UbTbJ6caB8uhcx2hYcWVvJAZYJRBo5HyyZfzMdRx8nvS+GyMg56fugMzzWnojREuQQ==
dependencies:
"@typescript-eslint/typescript-estree" "5.48.2"
"@typescript-eslint/utils" "5.48.2"
"@typescript-eslint/typescript-estree" "5.51.0"
"@typescript-eslint/utils" "5.51.0"
debug "^4.3.4"
tsutils "^3.21.0"
@@ -1938,10 +1950,10 @@
resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.33.0.tgz#a1e59036a3b53ae8430ceebf2a919dc7f9af6d72"
integrity sha512-zKp7CjQzLQImXEpLt2BUw1tvOMPfNoTAfb8l51evhYbOEEzdWyQNmHWWGPR6hwKJDAi+1VXSBmnhL9kyVTTOuQ==
"@typescript-eslint/types@5.48.2":
version "5.48.2"
resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.48.2.tgz#635706abb1ec164137f92148f06f794438c97b8e"
integrity sha512-hE7dA77xxu7ByBc6KCzikgfRyBCTst6dZQpwaTy25iMYOnbNljDT4hjhrGEJJ0QoMjrfqrx+j1l1B9/LtKeuqA==
"@typescript-eslint/types@5.51.0":
version "5.51.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.51.0.tgz#e7c1622f46c7eea7e12bbf1edfb496d4dec37c90"
integrity sha512-SqOn0ANn/v6hFn0kjvLwiDi4AzR++CBZz0NV5AnusT2/3y32jdc0G4woXPWHCumWtUXZKPAS27/9vziSsC9jnw==
"@typescript-eslint/typescript-estree@4.33.0":
version "4.33.0"
@@ -1956,29 +1968,29 @@
semver "^7.3.5"
tsutils "^3.21.0"
"@typescript-eslint/typescript-estree@5.48.2":
version "5.48.2"
resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.48.2.tgz#6e206b462942b32383582a6c9251c05021cc21b0"
integrity sha512-bibvD3z6ilnoVxUBFEgkO0k0aFvUc4Cttt0dAreEr+nrAHhWzkO83PEVVuieK3DqcgL6VAK5dkzK8XUVja5Zcg==
"@typescript-eslint/typescript-estree@5.51.0":
version "5.51.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.51.0.tgz#0ec8170d7247a892c2b21845b06c11eb0718f8de"
integrity sha512-TSkNupHvNRkoH9FMA3w7TazVFcBPveAAmb7Sz+kArY6sLT86PA5Vx80cKlYmd8m3Ha2SwofM1KwraF24lM9FvA==
dependencies:
"@typescript-eslint/types" "5.48.2"
"@typescript-eslint/visitor-keys" "5.48.2"
"@typescript-eslint/types" "5.51.0"
"@typescript-eslint/visitor-keys" "5.51.0"
debug "^4.3.4"
globby "^11.1.0"
is-glob "^4.0.3"
semver "^7.3.7"
tsutils "^3.21.0"
"@typescript-eslint/utils@5.48.2":
version "5.48.2"
resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.48.2.tgz#3777a91dcb22b8499a25519e06eef2e9569295a3"
integrity sha512-2h18c0d7jgkw6tdKTlNaM7wyopbLRBiit8oAxoP89YnuBOzCZ8g8aBCaCqq7h208qUTroL7Whgzam7UY3HVLow==
"@typescript-eslint/utils@5.51.0":
version "5.51.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.51.0.tgz#074f4fabd5b12afe9c8aa6fdee881c050f8b4d47"
integrity sha512-76qs+5KWcaatmwtwsDJvBk4H76RJQBFe+Gext0EfJdC3Vd2kpY2Pf//OHHzHp84Ciw0/rYoGTDnIAr3uWhhJYw==
dependencies:
"@types/json-schema" "^7.0.9"
"@types/semver" "^7.3.12"
"@typescript-eslint/scope-manager" "5.48.2"
"@typescript-eslint/types" "5.48.2"
"@typescript-eslint/typescript-estree" "5.48.2"
"@typescript-eslint/scope-manager" "5.51.0"
"@typescript-eslint/types" "5.51.0"
"@typescript-eslint/typescript-estree" "5.51.0"
eslint-scope "^5.1.1"
eslint-utils "^3.0.0"
semver "^7.3.7"
@@ -1991,12 +2003,12 @@
"@typescript-eslint/types" "4.33.0"
eslint-visitor-keys "^2.0.0"
"@typescript-eslint/visitor-keys@5.48.2":
version "5.48.2"
resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.48.2.tgz#c247582a0bcce467461d7b696513bf9455000060"
integrity sha512-z9njZLSkwmjFWUelGEwEbdf4NwKvfHxvGC0OcGN1Hp/XNDIcJ7D5DpPNPv6x6/mFvc1tQHsaWmpD/a4gOvvCJQ==
"@typescript-eslint/visitor-keys@5.51.0":
version "5.51.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.51.0.tgz#c0147dd9a36c0de758aaebd5b48cae1ec59eba87"
integrity sha512-Oh2+eTdjHjOFjKA27sxESlA87YPSOJafGCR0md5oeMdh1ZcCfAGCIOL216uTBAkAIptvLIfKQhl7lHxMJet4GQ==
dependencies:
"@typescript-eslint/types" "5.48.2"
"@typescript-eslint/types" "5.51.0"
eslint-visitor-keys "^3.3.0"
"@vue/babel-helper-vue-jsx-merge-props@^1.4.0":
@@ -2351,23 +2363,23 @@
vue-codemod "^0.0.5"
yaml-front-matter "^4.1.0"
"@vue/compiler-core@3.2.45", "@vue/compiler-core@^3.0.5":
version "3.2.45"
resolved "https://registry.yarnpkg.com/@vue/compiler-core/-/compiler-core-3.2.45.tgz#d9311207d96f6ebd5f4660be129fb99f01ddb41b"
integrity sha512-rcMj7H+PYe5wBV3iYeUgbCglC+pbpN8hBLTJvRiK2eKQiWqu+fG9F+8sW99JdL4LQi7Re178UOxn09puSXvn4A==
"@vue/compiler-core@3.2.47", "@vue/compiler-core@^3.0.5":
version "3.2.47"
resolved "https://registry.yarnpkg.com/@vue/compiler-core/-/compiler-core-3.2.47.tgz#3e07c684d74897ac9aa5922c520741f3029267f8"
integrity sha512-p4D7FDnQb7+YJmO2iPEv0SQNeNzcbHdGByJDsT4lynf63AFkOTFN07HsiRSvjGo0QrxR/o3d0hUyNCUnBU2Tig==
dependencies:
"@babel/parser" "^7.16.4"
"@vue/shared" "3.2.45"
"@vue/shared" "3.2.47"
estree-walker "^2.0.2"
source-map "^0.6.1"
"@vue/compiler-dom@3.2.45", "@vue/compiler-dom@^3.0.5":
version "3.2.45"
resolved "https://registry.yarnpkg.com/@vue/compiler-dom/-/compiler-dom-3.2.45.tgz#c43cc15e50da62ecc16a42f2622d25dc5fd97dce"
integrity sha512-tyYeUEuKqqZO137WrZkpwfPCdiiIeXYCcJ8L4gWz9vqaxzIQRccTSwSWZ/Axx5YR2z+LvpUbmPNXxuBU45lyRw==
"@vue/compiler-dom@3.2.47", "@vue/compiler-dom@^3.0.5":
version "3.2.47"
resolved "https://registry.yarnpkg.com/@vue/compiler-dom/-/compiler-dom-3.2.47.tgz#a0b06caf7ef7056939e563dcaa9cbde30794f305"
integrity sha512-dBBnEHEPoftUiS03a4ggEig74J2YBZ2UIeyfpcRM2tavgMWo4bsEfgCGsu+uJIL/vax9S+JztH8NmQerUo7shQ==
dependencies:
"@vue/compiler-core" "3.2.45"
"@vue/shared" "3.2.45"
"@vue/compiler-core" "3.2.47"
"@vue/shared" "3.2.47"
"@vue/compiler-sfc@2.7.14":
version "2.7.14"
@@ -2379,28 +2391,28 @@
source-map "^0.6.1"
"@vue/compiler-sfc@^3.2.45":
version "3.2.45"
resolved "https://registry.yarnpkg.com/@vue/compiler-sfc/-/compiler-sfc-3.2.45.tgz#7f7989cc04ec9e7c55acd406827a2c4e96872c70"
integrity sha512-1jXDuWah1ggsnSAOGsec8cFjT/K6TMZ0sPL3o3d84Ft2AYZi2jWJgRMjw4iaK0rBfA89L5gw427H4n1RZQBu6Q==
version "3.2.47"
resolved "https://registry.yarnpkg.com/@vue/compiler-sfc/-/compiler-sfc-3.2.47.tgz#1bdc36f6cdc1643f72e2c397eb1a398f5004ad3d"
integrity sha512-rog05W+2IFfxjMcFw10tM9+f7i/+FFpZJJ5XHX72NP9eC2uRD+42M3pYcQqDXVYoj74kHMSEdQ/WmCjt8JFksQ==
dependencies:
"@babel/parser" "^7.16.4"
"@vue/compiler-core" "3.2.45"
"@vue/compiler-dom" "3.2.45"
"@vue/compiler-ssr" "3.2.45"
"@vue/reactivity-transform" "3.2.45"
"@vue/shared" "3.2.45"
"@vue/compiler-core" "3.2.47"
"@vue/compiler-dom" "3.2.47"
"@vue/compiler-ssr" "3.2.47"
"@vue/reactivity-transform" "3.2.47"
"@vue/shared" "3.2.47"
estree-walker "^2.0.2"
magic-string "^0.25.7"
postcss "^8.1.10"
source-map "^0.6.1"
"@vue/compiler-ssr@3.2.45":
version "3.2.45"
resolved "https://registry.yarnpkg.com/@vue/compiler-ssr/-/compiler-ssr-3.2.45.tgz#bd20604b6e64ea15344d5b6278c4141191c983b2"
integrity sha512-6BRaggEGqhWht3lt24CrIbQSRD5O07MTmd+LjAn5fJj568+R9eUD2F7wMQJjX859seSlrYog7sUtrZSd7feqrQ==
"@vue/compiler-ssr@3.2.47":
version "3.2.47"
resolved "https://registry.yarnpkg.com/@vue/compiler-ssr/-/compiler-ssr-3.2.47.tgz#35872c01a273aac4d6070ab9d8da918ab13057ee"
integrity sha512-wVXC+gszhulcMD8wpxMsqSOpvDZ6xKXSVWkf50Guf/S+28hTAXPDYRTbLQ3EDkOP5Xz/+SY37YiwDquKbJOgZw==
dependencies:
"@vue/compiler-dom" "3.2.45"
"@vue/shared" "3.2.45"
"@vue/compiler-dom" "3.2.47"
"@vue/shared" "3.2.47"
"@vue/component-compiler-utils@^3.1.0", "@vue/component-compiler-utils@^3.3.0":
version "3.3.0"
@@ -2418,6 +2430,16 @@
optionalDependencies:
prettier "^1.18.2 || ^2.0.0"
"@vue/composition-api@1.7.1":
version "1.7.1"
resolved "https://registry.yarnpkg.com/@vue/composition-api/-/composition-api-1.7.1.tgz#aa6831be5a12817d93e89e247460c310dd7a3a32"
integrity sha512-xDWoEtxGXhH9Ku3ROYX/rzhcpt4v31hpPU5zF3UeVC/qxA3dChmqU8zvTUYoKh3j7rzpNsoFOwqsWG7XPMlaFA==
"@vue/devtools-api@^6.4.5":
version "6.5.0"
resolved "https://registry.yarnpkg.com/@vue/devtools-api/-/devtools-api-6.5.0.tgz#98b99425edee70b4c992692628fa1ea2c1e57d07"
integrity sha512-o9KfBeaBmCKl10usN4crU53fYtC1r7jJwdGKjPT24t348rHxgfpZ0xL3Xm/gLUYnc0oTp8LAmrxOeLyu6tbk2Q==
"@vue/eslint-config-typescript@^10.0.0":
version "10.0.0"
resolved "https://registry.yarnpkg.com/@vue/eslint-config-typescript/-/eslint-config-typescript-10.0.0.tgz#3b63c8cf276962cb89414857581b9b424acf2820"
@@ -2427,21 +2449,21 @@
"@typescript-eslint/parser" "^5.0.0"
vue-eslint-parser "^8.0.0"
"@vue/reactivity-transform@3.2.45":
version "3.2.45"
resolved "https://registry.yarnpkg.com/@vue/reactivity-transform/-/reactivity-transform-3.2.45.tgz#07ac83b8138550c83dfb50db43cde1e0e5e8124d"
integrity sha512-BHVmzYAvM7vcU5WmuYqXpwaBHjsS8T63jlKGWVtHxAHIoMIlmaMyurUSEs1Zcg46M4AYT5MtB1U274/2aNzjJQ==
"@vue/reactivity-transform@3.2.47":
version "3.2.47"
resolved "https://registry.yarnpkg.com/@vue/reactivity-transform/-/reactivity-transform-3.2.47.tgz#e45df4d06370f8abf29081a16afd25cffba6d84e"
integrity sha512-m8lGXw8rdnPVVIdIFhf0LeQ/ixyHkH5plYuS83yop5n7ggVJU+z5v0zecwEnX7fa7HNLBhh2qngJJkxpwEEmYA==
dependencies:
"@babel/parser" "^7.16.4"
"@vue/compiler-core" "3.2.45"
"@vue/shared" "3.2.45"
"@vue/compiler-core" "3.2.47"
"@vue/shared" "3.2.47"
estree-walker "^2.0.2"
magic-string "^0.25.7"
"@vue/shared@3.2.45":
version "3.2.45"
resolved "https://registry.yarnpkg.com/@vue/shared/-/shared-3.2.45.tgz#a3fffa7489eafff38d984e23d0236e230c818bc2"
integrity sha512-Ewzq5Yhimg7pSztDV+RH1UDKBzmtqieXQlpTVm2AwraoRL/Rks96mvd8Vgi7Lj+h+TH8dv7mXD3FRZR3TUvbSg==
"@vue/shared@3.2.47":
version "3.2.47"
resolved "https://registry.yarnpkg.com/@vue/shared/-/shared-3.2.47.tgz#e597ef75086c6e896ff5478a6bfc0a7aa4bbd14c"
integrity sha512-BHGyyGN3Q97EZx0taMQ+OLNuZcW3d37ZEVmEAyeoA9ERdGvm9Irc/0Fua8SNyOtV1w6BS4q25wbMzJujO9HIfQ==
"@vue/vue-loader-v15@npm:vue-loader@^15.9.7":
version "15.10.1"
@@ -2769,9 +2791,9 @@ acorn@^7.1.0, acorn@^7.4.0:
integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==
acorn@^8.0.4, acorn@^8.0.5, acorn@^8.5.0, acorn@^8.7.1, acorn@^8.8.0:
version "8.8.1"
resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.8.1.tgz#0a3f9cbecc4ec3bea6f0a80b66ae8dd2da250b73"
integrity sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA==
version "8.8.2"
resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.8.2.tgz#1b2f25db02af965399b9776b0c2c391276d37c4a"
integrity sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==
address@^1.1.2:
version "1.2.2"
@@ -3119,9 +3141,9 @@ astral-regex@^2.0.0:
integrity sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==
async-each@^1.0.1:
version "1.0.3"
resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.3.tgz#b727dbf87d7651602f06f4d4ac387f47d91b0cbf"
integrity sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ==
version "1.0.6"
resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.6.tgz#52f1d9403818c179b7561e11a5d1b77eb2160e77"
integrity sha512-c646jH1avxr+aVpndVMeAfYw7wAa6idufrlN3LPA4PmKS0QEGp6PIC9nwz0WQkkvBGAMEki3pFdtxaF39J9vvg==
async-retry@^1.2.1:
version "1.3.3"
@@ -3175,9 +3197,9 @@ available-typed-arrays@^1.0.5:
integrity sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==
axios@^1.2.0:
version "1.2.3"
resolved "https://registry.yarnpkg.com/axios/-/axios-1.2.3.tgz#31a3d824c0ebf754a004b585e5f04a5f87e6c4ff"
integrity sha512-pdDkMYJeuXLZ6Xj/Q5J3Phpe+jbGdsSzlQaFVkMQzRUL05+6+tetX8TV3p4HrU4kzuO9bt+io/yGQxuyxA/xcw==
version "1.3.2"
resolved "https://registry.yarnpkg.com/axios/-/axios-1.3.2.tgz#7ac517f0fa3ec46e0e636223fd973713a09c72b3"
integrity sha512-1M3O703bYqYuPhbHeya5bnhpYVsDDRyQSabNja04mZtboLNSuZ4YrltestrLXfHgmzua4TpUqRiVKbiQuo2epw==
dependencies:
follow-redirects "^1.15.0"
form-data "^4.0.0"
@@ -3664,14 +3686,14 @@ browserify-zlib@^0.2.0:
pako "~1.0.5"
browserslist@^4.0.0, browserslist@^4.14.5, browserslist@^4.16.3, browserslist@^4.16.6, browserslist@^4.21.3, browserslist@^4.21.4:
version "4.21.4"
resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.21.4.tgz#e7496bbc67b9e39dd0f98565feccdcb0d4ff6987"
integrity sha512-CBHJJdDmgjl3daYjN5Cp5kbTf1mUhZoS+beLklHIvkOWscs83YAhLlF3Wsh/lciQYAcbBJgTOD44VtG31ZM4Hw==
version "4.21.5"
resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.21.5.tgz#75c5dae60063ee641f977e00edd3cfb2fb7af6a7"
integrity sha512-tUkiguQGW7S3IhB7N+c2MV/HZPSCPAAiYBZXLsBhFB/PCy6ZKKsZrmBayHV9fdGV/ARIfJ14NkxKzRDjvp7L6w==
dependencies:
caniuse-lite "^1.0.30001400"
electron-to-chromium "^1.4.251"
node-releases "^2.0.6"
update-browserslist-db "^1.0.9"
caniuse-lite "^1.0.30001449"
electron-to-chromium "^1.4.284"
node-releases "^2.0.8"
update-browserslist-db "^1.0.10"
btoa@^1.2.1:
version "1.2.1"
@@ -3843,10 +3865,10 @@ caniuse-api@^3.0.0:
lodash.memoize "^4.1.2"
lodash.uniq "^4.5.0"
caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001400, caniuse-lite@^1.0.30001426:
version "1.0.30001447"
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001447.tgz#ef1f39ae38d839d7176713735a8e467a0a2523bd"
integrity sha512-bdKU1BQDPeEXe9A39xJnGtY0uRq/z5osrnXUw0TcK+EYno45Y+U7QU9HhHEyzvMDffpYadFXi3idnSNkcwLkTw==
caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001426, caniuse-lite@^1.0.30001449:
version "1.0.30001451"
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001451.tgz#2e197c698fc1373d63e1406d6607ea4617c613f1"
integrity sha512-XY7UbUpGRatZzoRft//5xOa69/1iGJRBlrieH6QYrkKLIFn3m7OVEJ81dSrKoy2BnKsdbX5cLrOispZNYo9v2w==
canvg@^3.0.6:
version "3.0.10"
@@ -4286,9 +4308,9 @@ content-disposition@0.5.4, content-disposition@^0.5.2:
safe-buffer "5.2.1"
content-type@~1.0.4:
version "1.0.4"
resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b"
integrity sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==
version "1.0.5"
resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.5.tgz#8b773162656d1d1086784c8f23a54ce6d73d7918"
integrity sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==
convert-source-map@^1.5.1, convert-source-map@^1.7.0:
version "1.9.0"
@@ -4718,9 +4740,9 @@ deepmerge@^1.5.2:
integrity sha512-95k0GDqvBjZavkuvzx/YqVLv/6YYa17fz6ILMSf7neqQITCPbnfEnQvEgMPNjH4kgobe7+WIL0yJEHku+H3qtQ==
deepmerge@^4.2.0, deepmerge@^4.2.2:
version "4.2.2"
resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.2.2.tgz#44d2ea3679b8f4d4ffba33f03d865fc1e7bf4955"
integrity sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==
version "4.3.0"
resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.3.0.tgz#65491893ec47756d44719ae520e0e2609233b59b"
integrity sha512-z2wJZXrmeHdvYJp/Ux55wIjqo81G5Bp4c+oELTW+7ar6SogWHajt5a9gO3s3IDaGSAXjDk0vlQKN3rms8ab3og==
default-gateway@^6.0.3:
version "6.0.3"
@@ -5003,10 +5025,10 @@ ejs@^3.1.6:
dependencies:
jake "^10.8.5"
electron-to-chromium@^1.4.251:
version "1.4.284"
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.284.tgz#61046d1e4cab3a25238f6bf7413795270f125592"
integrity sha512-M8WEXFuKXMYMVr45fo8mq0wUrrJHheiKZf6BArTKk9ZBYCKJEOU5H8cdWgDT+qCVZf7Na4lVUaZsA+h6uA9+PA==
electron-to-chromium@^1.4.284:
version "1.4.289"
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.289.tgz#02b59b1096486fc0bd4871a0484d8317802c6658"
integrity sha512-relLdMfPBxqGCxy7Gyfm1HcbRPcFUJdlgnCPVgQ23sr1TvUrRJz0/QPoGP0+x41wOVSTN/Wi3w6YDgHiHJGOzg==
elliptic@^6.5.3:
version "6.5.4"
@@ -5030,9 +5052,9 @@ emoji-mart-vue-fast@^12.0.1:
core-js "^3.23.5"
emoji-mart@^5.4.0:
version "5.5.1"
resolved "https://registry.yarnpkg.com/emoji-mart/-/emoji-mart-5.5.1.tgz#b0c5bd11b3b9558fd8f5e35225369628e0226d4c"
integrity sha512-16hsygz4oz7BVi0tGEWZRQXs4+KC3IyR1s2uftRECYyLstZHoIUAceZ+VvEMhEZUpWtEKMWBTjgGJJVDBuOIVQ==
version "5.5.2"
resolved "https://registry.yarnpkg.com/emoji-mart/-/emoji-mart-5.5.2.tgz#3ddbaf053139cf4aa217650078bc1c50ca8381af"
integrity sha512-Sqc/nso4cjxhOwWJsp9xkVm8OF5c+mJLZJFoFfzRuKO+yWiN7K8c96xmtughYb0d/fZ8UC6cLIQ/p4BR6Pv3/A==
emoji-regex@^7.0.1:
version "7.0.3"
@@ -5827,9 +5849,9 @@ flatted@^3.1.0:
integrity sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==
flow-parser@0.*:
version "0.198.1"
resolved "https://registry.yarnpkg.com/flow-parser/-/flow-parser-0.198.1.tgz#56a77de3637c0f39284d4a112868f0cbfaa72012"
integrity sha512-WgmXdj+QWApMqtnMTeG7bF6tpX/+jsH5r/i61ukFCSXVgsaldLa/KOy+hcwQ3dbxsMGYM5iLQme6Z0/s0z2OkQ==
version "0.199.1"
resolved "https://registry.yarnpkg.com/flow-parser/-/flow-parser-0.199.1.tgz#d2e37d3ccd3a4301738a429079a41320a54ada57"
integrity sha512-Mt+GFUQYij3miM7Z6o8E3aHTGXZKSOhvlCFgdQRoi6fkWfhyijnoX51zpOxM5PmZuiV6gallWhDZzwOsWxRutg==
flush-write-stream@^1.0.0:
version "1.1.1"
@@ -6144,9 +6166,9 @@ globals@^11.1.0:
integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==
globals@^13.6.0, globals@^13.9.0:
version "13.19.0"
resolved "https://registry.yarnpkg.com/globals/-/globals-13.19.0.tgz#7a42de8e6ad4f7242fbcca27ea5b23aca367b5c8"
integrity sha512-dkQ957uSRWHw7CFXLUtUHQI3g3aWApYhfNR2O6jn/907riyTYKVBmxYVROkBcY614FSSeSJh7Xm7SrUWCxvJMQ==
version "13.20.0"
resolved "https://registry.yarnpkg.com/globals/-/globals-13.20.0.tgz#ea276a1e508ffd4f1612888f9d1bad1e2717bf82"
integrity sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==
dependencies:
type-fest "^0.20.2"
@@ -6216,6 +6238,11 @@ graceful-fs@^4.1.10, graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.
resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.10.tgz#147d3a006da4ca3ce14728c7aefc287c367d7a6c"
integrity sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==
grapheme-splitter@^1.0.4:
version "1.0.4"
resolved "https://registry.yarnpkg.com/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz#9cf3a665c6247479896834af35cf1dbb4400767e"
integrity sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==
graphql-subscriptions@^1.2.0:
version "1.2.1"
resolved "https://registry.yarnpkg.com/graphql-subscriptions/-/graphql-subscriptions-1.2.1.tgz#2142b2d729661ddf967b7388f7cf1dd4cf2e061d"
@@ -8051,9 +8078,9 @@ no-case@^3.0.4:
tslib "^2.0.3"
node-abort-controller@^3.0.1:
version "3.0.1"
resolved "https://registry.yarnpkg.com/node-abort-controller/-/node-abort-controller-3.0.1.tgz#f91fa50b1dee3f909afabb7e261b1e1d6b0cb74e"
integrity sha512-/ujIVxthRs+7q6hsdjHMaj8hRG9NuWmwrz+JdRwZ14jdFoKSkm+vDsCbF9PLpnSqjaWQJuTmVtcWHNLr+vrOFw==
version "3.1.1"
resolved "https://registry.yarnpkg.com/node-abort-controller/-/node-abort-controller-3.1.1.tgz#a94377e964a9a37ac3976d848cb5c765833b8548"
integrity sha512-AGK2yQKIjRuqnc6VkX2Xj5d+QW8xZ87pa1UK6yA6ouUyuxfHuMP6umE5QK7UmTeOAymo+Zx1Fxiuw9rVx8taHQ==
node-dir@^0.1.17:
version "0.1.17"
@@ -8063,9 +8090,9 @@ node-dir@^0.1.17:
minimatch "^3.0.2"
node-fetch@^2.6.7:
version "2.6.8"
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.8.tgz#a68d30b162bc1d8fd71a367e81b997e1f4d4937e"
integrity sha512-RZ6dBYuj8dRSfxpUSu+NsdF1dpPpluJxwOp+6IoDp/sH2QNDSvurYsAa+F1WxY2RjA1iP93xhcsUoYbF2XBqVg==
version "2.6.9"
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.9.tgz#7c7f744b5cc6eb5fd404e0c7a9fec630a55657e6"
integrity sha512-DJm/CJkZkRjKKj4Zi4BsKVZh3ValV5IR5s7LVZnW+6YMh0W1BfNA8XSs6DLMGYlId5F3KnA70uu2qepcR08Qqg==
dependencies:
whatwg-url "^5.0.0"
@@ -8115,10 +8142,10 @@ node-notifier@^10.0.0:
uuid "^8.3.2"
which "^2.0.2"
node-releases@^2.0.6:
version "2.0.8"
resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.8.tgz#0f349cdc8fcfa39a92ac0be9bc48b7706292b9ae"
integrity sha512-dFSmB8fFHEH/s81Xi+Y/15DQY6VHW81nXRj86EMSL3lmuTmK1e+aT4wrFCkTbm+gSwkw4KpX+rT/pMM2c1mF+A==
node-releases@^2.0.8:
version "2.0.10"
resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.10.tgz#c311ebae3b6a148c89b1813fd7c4d3c024ef537f"
integrity sha512-5GFldHPXVG/YZmFzJvKK2zDSzPKhEp0+ZR5SVaoSag9fsL5YgHbUHDfnG5494ISANDcK4KwPXAx2xqVEydmd7w==
normalize-package-data@^2.5.0:
version "2.5.0"
@@ -8282,9 +8309,9 @@ onetime@^5.1.0, onetime@^5.1.2:
mimic-fn "^2.1.0"
open@^8.0.2, open@^8.0.9:
version "8.4.0"
resolved "https://registry.yarnpkg.com/open/-/open-8.4.0.tgz#345321ae18f8138f82565a910fdc6b39e8c244f8"
integrity sha512-XgFPPM+B28FtCCgSb9I+s9szOC1vZRSwgWsRUA5ylIxRTgKozqjOCrVOqGsYABPYK5qnfqClxZTFBa8PKt2v6Q==
version "8.4.1"
resolved "https://registry.yarnpkg.com/open/-/open-8.4.1.tgz#2ab3754c07f5d1f99a7a8d6a82737c95e3101cff"
integrity sha512-/4b7qZNhv6Uhd7jjnREh1NjnPxlTq+XNWPG88Ydkj5AILcA5m3ajvcg57pB24EQjKv0dK62XnDqk9c/hkIG5Kg==
dependencies:
define-lazy-prop "^2.0.0"
is-docker "^2.1.1"
@@ -8625,6 +8652,14 @@ pify@^4.0.1:
resolved "https://registry.yarnpkg.com/pify/-/pify-4.0.1.tgz#4b2cd25c50d598735c50292224fd8c6df41e3231"
integrity sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==
pinia@^2.0.30:
version "2.0.30"
resolved "https://registry.yarnpkg.com/pinia/-/pinia-2.0.30.tgz#b18a581dad6821ed5fbebfaf631229480ea9d2d9"
integrity sha512-q6DUmxWwe/mQgg+55QQjykpKC+aGeGdaJV3niminl19V08dE+LRTvSEuqi6/NLSGCKHI49KGL6tMNEOssFiMyA==
dependencies:
"@vue/devtools-api" "^6.4.5"
vue-demi "*"
pinkie-promise@^2.0.0:
version "2.0.1"
resolved "https://registry.yarnpkg.com/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa"
@@ -8962,9 +8997,9 @@ prepend-http@^2.0.0:
integrity sha512-ravE6m9Atw9Z/jjttRUZ+clIXogdghyZAuWJ3qEzjT+jI/dL1ifAqhZeC5VHzQp1MSt1+jxKkFNemj/iO7tVUA==
"prettier@^1.18.2 || ^2.0.0":
version "2.8.3"
resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.8.3.tgz#ab697b1d3dd46fb4626fbe2f543afe0cc98d8632"
integrity sha512-tJ/oJ4amDihPoufT5sM0Z1SKEuKay8LfVAMlbbhnnkvt6BUserZylqo2PN+p9KeljLr0OHa2rXHU1T8reeoTrw==
version "2.8.4"
resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.8.4.tgz#34dd2595629bfbb79d344ac4a91ff948694463c3"
integrity sha512-vIS4Rlc2FNh0BySk3Wkd6xmwxB0FpOndW5fisM5H8hsZSxU2VWVB5CWIkIjWvrHjIhxk2g3bfMKM87zNTrZddw==
pretty-bytes@^5.3.0, pretty-bytes@^5.4.1:
version "5.6.0"
@@ -9317,22 +9352,17 @@ regexpp@^3.1.0, regexpp@^3.2.0:
integrity sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==
regexpu-core@^5.2.1:
version "5.2.2"
resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-5.2.2.tgz#3e4e5d12103b64748711c3aad69934d7718e75fc"
integrity sha512-T0+1Zp2wjF/juXMrMxHxidqGYn8U4R+zleSJhX9tQ1PUsS8a9UtYfbsF9LdiVgNX3kiX8RNaKM42nfSgvFJjmw==
version "5.3.0"
resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-5.3.0.tgz#4d0d044b76fedbad6238703ae84bfdedee2cf074"
integrity sha512-ZdhUQlng0RoscyW7jADnUZ25F5eVtHdMyXSb2PiwafvteRAOJUjFoUPEYZSIfP99fBIs3maLIRfpEddT78wAAQ==
dependencies:
"@babel/regjsgen" "^0.8.0"
regenerate "^1.4.2"
regenerate-unicode-properties "^10.1.0"
regjsgen "^0.7.1"
regjsparser "^0.9.1"
unicode-match-property-ecmascript "^2.0.0"
unicode-match-property-value-ecmascript "^2.1.0"
regjsgen@^0.7.1:
version "0.7.1"
resolved "https://registry.yarnpkg.com/regjsgen/-/regjsgen-0.7.1.tgz#ee5ef30e18d3f09b7c369b76e7c2373ed25546f6"
integrity sha512-RAt+8H2ZEzHeYWxZ3H2z6tF18zyyOnlcdaafLrm21Bguj7uZy6ULibiAFdXEtKQY4Sy7wDTwDiOazasMLc4KPA==
regjsparser@^0.9.1:
version "0.9.1"
resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.9.1.tgz#272d05aa10c7c1f67095b1ff0addae8442fc5709"
@@ -9843,9 +9873,9 @@ shebang-regex@^3.0.0:
integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==
shell-quote@^1.7.3:
version "1.7.4"
resolved "https://registry.yarnpkg.com/shell-quote/-/shell-quote-1.7.4.tgz#33fe15dee71ab2a81fcbd3a52106c5cfb9fb75d8"
integrity sha512-8o/QEhSSRb1a5i7TFR0iM4G16Z0vYB2OQVs4G3aAFXjn3T6yEx8AZxy1PgDF7I00LZHYA3WxaSYIf5e5sAX8Rw==
version "1.8.0"
resolved "https://registry.yarnpkg.com/shell-quote/-/shell-quote-1.8.0.tgz#20d078d0eaf71d54f43bd2ba14a1b5b9bfa5c8ba"
integrity sha512-QHsz8GgQIGKlRi24yFc6a6lN69Idnx634w49ay6+jA5yFh7a1UY+4Rp6HPx/L/1zcEDPEij8cIsiqR6bQsE5VQ==
shellwords@^0.1.1:
version "0.1.1"
@@ -10546,9 +10576,9 @@ terser@^4.1.2, terser@^4.6.2:
source-map-support "~0.5.12"
terser@^5.0.0, terser@^5.10.0, terser@^5.14.1:
version "5.16.1"
resolved "https://registry.yarnpkg.com/terser/-/terser-5.16.1.tgz#5af3bc3d0f24241c7fb2024199d5c461a1075880"
integrity sha512-xvQfyfA1ayT0qdK47zskQgRZeWLoOQ8JQ6mIgRGVNwZKdQMU+5FkCBjmv4QjcrTzyZquRw2FVtlJSRUmMKQslw==
version "5.16.3"
resolved "https://registry.yarnpkg.com/terser/-/terser-5.16.3.tgz#3266017a9b682edfe019b8ecddd2abaae7b39c6b"
integrity sha512-v8wWLaS/xt3nE9dgKEWhNUFP6q4kngO5B8eYFUuebsu7Dw/UNAnpUod6UHo04jSSkv8TzKHjZDSd7EXdDQAl8Q==
dependencies:
"@jridgewell/source-map" "^0.3.2"
acorn "^8.5.0"
@@ -10736,9 +10766,9 @@ tslib@^1.8.1, tslib@^1.9.0:
integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==
tslib@^2.0.1, tslib@^2.0.3, tslib@^2.1.0, tslib@^2.4.0:
version "2.4.1"
resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.4.1.tgz#0d0bfbaac2880b91e22df0768e55be9753a5b17e"
integrity sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA==
version "2.5.0"
resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.5.0.tgz#42bfed86f5787aeb41d031866c8f402429e0fddf"
integrity sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==
tsutils@^3.21.0:
version "3.21.0"
@@ -10824,9 +10854,9 @@ typescript@~4.5.5:
integrity sha512-TCTIul70LyWe6IJWT8QSYeA54WQe8EjQFU4wY52Fasj5UKx88LNYKCgBEHcOMOrFF1rKGbD8v/xcNWVUq9SymA==
typescript@~4.9.3:
version "4.9.4"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.9.4.tgz#a2a3d2756c079abda241d75f149df9d561091e78"
integrity sha512-Uz+dTXYzxXXbsFpM86Wh3dKCxrQqUcVMxwU54orwlJjOpO3ao8L7j5lH+dWfTwgCwIuM9GQ2kvVotzYJMXTBZg==
version "4.9.5"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.9.5.tgz#095979f9bcc0d09da324d58d03ce8f8374cbe65a"
integrity sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==
unbox-primitive@^1.0.2:
version "1.0.2"
@@ -10935,7 +10965,7 @@ upath@^1.1.1, upath@^1.1.2, upath@^1.2.0:
resolved "https://registry.yarnpkg.com/upath/-/upath-1.2.0.tgz#8f66dbcd55a883acdae4408af8b035a5044c1894"
integrity sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==
update-browserslist-db@^1.0.9:
update-browserslist-db@^1.0.10:
version "1.0.10"
resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.0.10.tgz#0f54b876545726f17d00cd9a2561e6dade943ff3"
integrity sha512-OztqDenkfFkbSG+tRxBeAnCVPckDBcvibKd35yDONx6OU8N7sqgwc7rCbkJ/WcYtVRZ4ba68d6byhC21GFh7sQ==
@@ -11128,6 +11158,11 @@ vue-cookies@^1.8.2:
resolved "https://registry.yarnpkg.com/vue-cookies/-/vue-cookies-1.8.2.tgz#39515fa09ebb585a50ac86c0e182a6b9307dc6ad"
integrity sha512-+NfoC5l+7ybuVwpnqsf52qndnoYMjEb4EFhX4/j9RzzQP00dNzuJELsWuW2p8omNUzNlSgWGVyyWoOeJr347tw==
vue-demi@*:
version "0.13.11"
resolved "https://registry.yarnpkg.com/vue-demi/-/vue-demi-0.13.11.tgz#7d90369bdae8974d87b1973564ad390182410d99"
integrity sha512-IR8HoEEGM65YY3ZJYAjMlKygDQn25D5ajNFNoKh9RSDMQtlzCxtfQjdQgv9jjK+m3377SsJXY8ysq8kLCZL25A==
vue-eslint-parser@^8.0.0, vue-eslint-parser@^8.0.1:
version "8.3.0"
resolved "https://registry.yarnpkg.com/vue-eslint-parser/-/vue-eslint-parser-8.3.0.tgz#5d31129a1b3dd89c0069ca0a1c88f970c360bd0d"
@@ -11248,11 +11283,6 @@ vuedraggable@^2.24.3:
dependencies:
sortablejs "1.10.2"
vuex@^3.6.0:
version "3.6.2"
resolved "https://registry.yarnpkg.com/vuex/-/vuex-3.6.2.tgz#236bc086a870c3ae79946f107f16de59d5895e71"
integrity sha512-ETW44IqCgBpVomy520DT5jf8n0zoCac+sxWnn+hMe/CzaSejb/eVw2YToiXYX+Ex/AuHHia28vWTq4goAexFbw==
watch-size@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/watch-size/-/watch-size-2.0.0.tgz#096ee28d0365bd7ea03d9c8bf1f2f50a73be1474"
@@ -11575,7 +11605,7 @@ word-wrap@^1.2.3:
resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c"
integrity sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==
workbox-background-sync@6.5.4:
workbox-background-sync@6.5.4, workbox-background-sync@^6.5.4:
version "6.5.4"
resolved "https://registry.yarnpkg.com/workbox-background-sync/-/workbox-background-sync-6.5.4.tgz#3141afba3cc8aa2ae14c24d0f6811374ba8ff6a9"
integrity sha512-0r4INQZMyPky/lj4Ou98qxcThrETucOde+7mRGJl13MPJugQNKeZQOdIJe/1AchOP23cTqHcN/YVpD6r8E6I8g==
@@ -11882,7 +11912,7 @@ workbox-webpack-plugin@^6.5.4:
webpack-sources "^1.4.3"
workbox-build "6.5.4"
workbox-window@6.5.4:
workbox-window@6.5.4, workbox-window@^6.5.4:
version "6.5.4"
resolved "https://registry.yarnpkg.com/workbox-window/-/workbox-window-6.5.4.tgz#d991bc0a94dff3c2dbb6b84558cff155ca878e91"
integrity sha512-HnLZJDwYBE+hpG25AQBO8RUWBJRaCsI9ksQJEp3aCOFCaG5kqaToAYXFRAHxzRluM2cQbGzdQF5rjKPWPA1fug==