Merge branch 'mealie-next' into fix/translation-issues-when-scraping

This commit is contained in:
Michael Genson 2023-12-11 13:01:26 -06:00 committed by GitHub
commit 449eeb0d53
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
74 changed files with 505 additions and 672 deletions

View File

@ -41,7 +41,8 @@
// Use 'forwardPorts' to make a list of ports inside the container available locally.
"forwardPorts": [
3000,
9000
9000,
24678 // used by nuxt when hot-reloading using polling
],
// Use 'onCreateCommand' to run commands at the end of container creation.
// Use 'postCreateCommand' to run commands after the container is created.

View File

@ -1,7 +1,7 @@
---
name: Bug Report
description: "Submit a bug for the latest version of Mealie"
title: "[BUG] - YOUR TITLE"
title: "[BUG] - YOUR DESCRIPTIVE TITLE GOES HERE"
labels: ["bug", "triage"]
body:
- type: checkboxes
@ -14,7 +14,7 @@ body:
options:
- label: This is not a feature request.
required: true
- label: I added a very descriptive title to this issue.
- label: I added a very descriptive title to this issue (title field is above this).
required: true
- label: I used the GitHub search to find a similar issue and didn't find it.
required: true
@ -61,7 +61,8 @@ body:
- Docker (Windows)
- Docker (Synology)
- Unraid
- Other
- TrueNAS
- Other (please specify below)
validations:
required: true
- type: textarea

View File

@ -36,7 +36,7 @@ jobs:
# Steps
steps:
- name: Check out repository
uses: actions/checkout@v3
uses: actions/checkout@v4
- name: Set up python
uses: actions/setup-python@v4
@ -60,7 +60,7 @@ jobs:
id: cache-validate
if: steps.cached-poetry-dependencies.outputs.cache-hit == 'true'
run: |
echo "import black;print('venv good?')" > test.py && poetry run python test.py && echo ::set-output name=cache-hit-success::true
echo "import black;print('venv good?')" > test.py && poetry run python test.py && echo "cache-hit-success=true" >> $GITHUB_OUTPUT
rm test.py
continue-on-error: true

View File

@ -20,26 +20,26 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v3
uses: actions/checkout@v4
- name: Log in to the Container registry (ghcr.io)
uses: docker/login-action@v2
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Log in to the Container registry (dockerhub)
uses: docker/login-action@v2
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Set up QEMU
uses: docker/setup-qemu-action@v2
uses: docker/setup-qemu-action@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
uses: docker/setup-buildx-action@v3
- name: Override __init__.py
run: |

View File

@ -9,20 +9,20 @@ jobs:
steps:
- name: Checkout 🛎
uses: actions/checkout@master
uses: actions/checkout@v4
- name: Setup node env 🏗
uses: actions/setup-node@v3.7.0
uses: actions/setup-node@v4.0.0
with:
node-version: 16
check-latest: true
- name: Get yarn cache directory path 🛠
id: yarn-cache-dir-path
run: echo "::set-output name=dir::$(yarn cache dir)"
run: echo "dir=$(yarn cache dir)" >> $GITHUB_OUTPUT
- name: Cache node_modules 📦
uses: actions/cache@v3.3.1
uses: actions/cache@v3.3.2
id: yarn-cache # use this to check for `cache-hit` (`steps.yarn-cache.outputs.cache-hit != 'true'`)
with:
path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
@ -47,20 +47,20 @@ jobs:
steps:
- name: Checkout 🛎
uses: actions/checkout@master
uses: actions/checkout@v4
- name: Setup node env 🏗
uses: actions/setup-node@v3.7.0
uses: actions/setup-node@v4.0.0
with:
node-version: 16
check-latest: true
- name: Get yarn cache directory path 🛠
id: yarn-cache-dir-path
run: echo "::set-output name=dir::$(yarn cache dir)"
run: echo "dir=$(yarn cache dir)" >> $GITHUB_OUTPUT
- name: Cache node_modules 📦
uses: actions/cache@v3.3.1
uses: actions/cache@v3.3.2
id: yarn-cache # use this to check for `cache-hit` (`steps.yarn-cache.outputs.cache-hit != 'true'`)
with:
path: ${{ steps.yarn-cache-dir-path.outputs.dir }}

View File

@ -11,7 +11,7 @@ jobs:
fail-fast: true
steps:
- name: Checkout code
uses: actions/checkout@v3
uses: actions/checkout@v4
- name: Build Dockerfile
run: |

View File

@ -14,8 +14,8 @@
"webp"
],
"editor.codeActionsOnSave": {
"source.fixAll.eslint": true,
"source.organizeImports": false
"source.fixAll.eslint": "explicit",
"source.organizeImports": "never"
},
"editor.formatOnSave": true,
"eslint.workingDirectories": [

View File

@ -9,7 +9,7 @@
<!-- PROJECT LOGO -->
<br />
<p align="center">
<a href="https://github.com/hay-kot/mealie">
<a href="https://github.com/mealie-recipes/mealie">
<svg style="width:100px;height:100px" viewBox="0 0 24 24">
<path fill="currentColor" d="M8.1,13.34L3.91,9.16C2.35,7.59 2.35,5.06 3.91,3.5L10.93,10.5L8.1,13.34M13.41,13L20.29,19.88L18.88,21.29L12,14.41L5.12,21.29L3.71,19.88L13.36,10.22L13.16,10C12.38,9.23 12.38,7.97 13.16,7.19L17.5,2.82L18.43,3.74L15.19,7L16.15,7.94L19.39,4.69L20.31,5.61L17.06,8.85L18,9.81L21.26,6.56L22.18,7.5L17.81,11.84C17.03,12.62 15.77,12.62 15,11.84L14.78,11.64L13.41,13Z" />
</svg>
@ -21,12 +21,12 @@
A Place for All Your Recipes
<br />
<a href="https://nightly.mealie.io"><strong>Explore the docs »</strong></a>
<a href="https://github.com/hay-kot/mealie">
<a href="https://github.com/mealie-recipes/mealie">
</a>
<br />
<a href="https://demo.mealie.io/">View Demo</a>
·
<a href="https://github.com/hay-kot/mealie/issues">Report Bug</a>
<a href="https://github.com/mealie-recipes/mealie/issues">Report Bug</a>
·
<a href="https://github.com/mealie-recipes/mealie/pkgs/container/mealie">GitHub Container Registry</a>
</p>
@ -76,17 +76,17 @@ Thanks to Linode for providing Hosting for the Demo, Beta, and Documentation sit
<!-- MARKDOWN LINKS & IMAGES -->
<!-- https://www.markdownguide.org/basic-syntax/#reference-style-links -->
[contributors-shield]: https://img.shields.io/github/contributors/hay-kot/mealie.svg?style=flat-square
[contributors-shield]: https://img.shields.io/github/contributors/mealie-recipes/mealie.svg?style=flat-square
[docker-pull]: https://img.shields.io/docker/pulls/hkotel/mealie
[contributors-url]: https://github.com/hay-kot/mealie/graphs/contributors
[forks-shield]: https://img.shields.io/github/forks/hay-kot/mealie.svg?style=flat-square
[forks-url]: https://github.com/hay-kot/mealie/network/members
[stars-shield]: https://img.shields.io/github/stars/hay-kot/mealie.svg?style=flat-square
[stars-url]: https://github.com/hay-kot/mealie/stargazers
[issues-shield]: https://img.shields.io/github/issues/hay-kot/mealie.svg?style=flat-square
[issues-url]: https://github.com/hay-kot/mealie/issues
[license-shield]: https://img.shields.io/github/license/hay-kot/mealie.svg?style=flat-square
[license-url]: https://github.com/hay-kot/mealie/blob/mealie-next/LICENSE
[contributors-url]: https://github.com/mealie-recipes/mealie/graphs/contributors
[forks-shield]: https://img.shields.io/github/forks/mealie-recipes/mealie.svg?style=flat-square
[forks-url]: https://github.com/mealie-recipes/mealie/network/members
[stars-shield]: https://img.shields.io/github/stars/mealie-recipes/mealie.svg?style=flat-square
[stars-url]: https://github.com/mealie-recipes/mealie/stargazers
[issues-shield]: https://img.shields.io/github/issues/mealie-recipes/mealie.svg?style=flat-square
[issues-url]: https://github.com/mealie-recipes/mealie/issues
[license-shield]: https://img.shields.io/github/license/mealie-recipes/mealie.svg?style=flat-square
[license-url]: https://github.com/mealie-recipes/mealie/blob/mealie-next/LICENSE
[linkedin-shield]: https://img.shields.io/badge/-LinkedIn-black.svg?style=flat-square&logo=linkedin&colorB=555
[linkedin-url]: https://linkedin.com/in/hay-kot
[product-screenshot]: docs/docs/assets/img/home_screenshot.png

View File

@ -62,7 +62,7 @@ A quality update with major props to [zackbcom](https://github.com/zackbcom) for
### Recipes
- Added user feedback on bad URL
- Better backend data validation for updating recipes, avoid small syntax errors corrupting database entry. [Closes #8](https://github.com/hay-kot/mealie/issues/8)
- Better backend data validation for updating recipes, avoid small syntax errors corrupting database entry. [Closes #8](https://github.com/mealie-recipes/mealie/issues/8)
- Fixed spacing Closes while editing new recipes in JSON
## v0.0.0 - Initial Pre-release

View File

@ -5,7 +5,7 @@
**Database Version: v0.4.0**
!!! error "Breaking Changes"
1. With a recent refactor some users been experiencing issues with an environmental variable not being set correct. If you are experiencing issues, please provide your comments [Here](https://github.com/hay-kot/mealie/issues/281).
1. With a recent refactor some users been experiencing issues with an environmental variable not being set correct. If you are experiencing issues, please provide your comments [Here](https://github.com/mealie-recipes/mealie/issues/281).
2. If you are a developer, you may experience issues with development as a new environmental variable has been introduced. Setting `PRODUCTION=false` will allow you to develop as normal.
@ -31,4 +31,4 @@
- Unify Logger across the backend
- mealie.log and last_recipe.json are now downloadable from the frontend from the /admin/about
- New download schema where you request a token and then use that token to hit a single endpoint to download a file. This is a notable change if you are using the API to download backups.
- Recipe images can now be added directly from a URL - [See #117 for details](https://github.com/hay-kot/mealie/issues/117)
- Recipe images can now be added directly from a URL - [See #117 for details](https://github.com/mealie-recipes/mealie/issues/117)

View File

@ -8,7 +8,7 @@
- Fixed #617 - Section behavior when adding a step
- Fixed #615 - Recipe Settings are not available when creating new recipe
- Fixed #625 - API of today's image returns strange characters
- Fixed [#590](https://github.com/hay-kot/mealie/issues/590) - Duplicate Events when using Gunicorn Workers
- Fixed [#590](https://github.com/mealie-recipes/mealie/issues/590) - Duplicate Events when using Gunicorn Workers
## Features and Improvements

View File

@ -6,14 +6,14 @@
- FastAPI to 0.78.0
- Recipe Ingredient Editor
- [#1140](https://github.com/hay-kot/mealie/issues/1140) - Error in processing the quantity of ingredients #1140 - UI Now prevents entering not-allowed characters in quantity field
- [#1140](https://github.com/mealie-recipes/mealie/issues/1140) - Error in processing the quantity of ingredients #1140 - UI Now prevents entering not-allowed characters in quantity field
- UI now allows no value to be set in addition to a zero (0) value.
- [#1237](https://github.com/hay-kot/mealie/issues/1237) - UI: Saving a 0 quantity ingredient displays 0 until the page is refreshed #1237 - UI Now properly reacts to changes in the quantity field.
- [#1237](https://github.com/mealie-recipes/mealie/issues/1237) - UI: Saving a 0 quantity ingredient displays 0 until the page is refreshed #1237 - UI Now properly reacts to changes in the quantity field.
- Fix Mealie v0.5.x migration issue [#1183](https://github.com/hay-kot/mealie/issues/1183)
- Fix Mealie v0.5.x migration issue [#1183](https://github.com/mealie-recipes/mealie/issues/1183)
- Consolidated Frontend Types thanks to [@PFischbeck](https://github.com/Fischbeck)
- Added support for SSL/No Auth Email [@nkringle](https://github.com/nkringle)
- [Implement several notifications for server actions ](https://github.com/hay-kot/mealie/pull/1234)[@miroito](https://github.com/Miroito)
- [Implement several notifications for server actions ](https://github.com/mealie-recipes/mealie/pull/1234)[@miroito](https://github.com/Miroito)
- Fix display issue for shared recipe rendering on server [@PFischbeck](https://github.com/Fischbeck)
## v1.0.0b - 2022-05-09
@ -36,7 +36,7 @@
- Mealie now stores the original text from parsed ingredients, with the ability to peak at the original text from a recipe. [@miroito](https://github.com/Miroito)
- Added some management / utility functions for administrators to manage data and cleanup artifacts from the file system.
- Fix clear url action in recipe creation [#1101](https://github.com/hay-kot/mealie/pull/1101) [@miroito](https://github.com/Miroito)
- Fix clear url action in recipe creation [#1101](https://github.com/mealie-recipes/mealie/pull/1101) [@miroito](https://github.com/Miroito)
- Add group statistics calculations and data storage measurements
- No hard limits are currently imposed on groups - though this may be implemented in the future.

View File

@ -1,29 +1,29 @@
### Bug Fixes
- Bump isomorphic-dompurify from 0.18.0 to 0.19.0 in /frontend ([#1257](https://github.com/hay-kot/mealie/issues/1257))
- Bump @nuxtjs/auth-next in /frontend ([#1265](https://github.com/hay-kot/mealie/issues/1265))
- Bad dev dependency ([#1281](https://github.com/hay-kot/mealie/issues/1281))
- Add touch support for mealplanner delete ([#1298](https://github.com/hay-kot/mealie/issues/1298))
- Bump isomorphic-dompurify from 0.18.0 to 0.19.0 in /frontend ([#1257](https://github.com/mealie-recipes/mealie/issues/1257))
- Bump @nuxtjs/auth-next in /frontend ([#1265](https://github.com/mealie-recipes/mealie/issues/1265))
- Bad dev dependency ([#1281](https://github.com/mealie-recipes/mealie/issues/1281))
- Add touch support for mealplanner delete ([#1298](https://github.com/mealie-recipes/mealie/issues/1298))
### Documentation
- Add references for VSCode dev containers ([#1299](https://github.com/hay-kot/mealie/issues/1299))
- Docker-compose.dev.yml is currently not functional ([#1300](https://github.com/hay-kot/mealie/issues/1300))
- Add references for VSCode dev containers ([#1299](https://github.com/mealie-recipes/mealie/issues/1299))
- Docker-compose.dev.yml is currently not functional ([#1300](https://github.com/mealie-recipes/mealie/issues/1300))
### Features
- Add reports to bulk recipe import (url) ([#1294](https://github.com/hay-kot/mealie/issues/1294))
- Rewrite print implementation to support new ing ([#1305](https://github.com/hay-kot/mealie/issues/1305))
- Add reports to bulk recipe import (url) ([#1294](https://github.com/mealie-recipes/mealie/issues/1294))
- Rewrite print implementation to support new ing ([#1305](https://github.com/mealie-recipes/mealie/issues/1305))
### Miscellaneous Tasks
- Github stalebot changes ([#1271](https://github.com/hay-kot/mealie/issues/1271))
- Bump eslint-plugin-nuxt in /frontend ([#1258](https://github.com/hay-kot/mealie/issues/1258))
- Bump @vue/runtime-dom in /frontend ([#1259](https://github.com/hay-kot/mealie/issues/1259))
- Bump nuxt-vite from 0.1.3 to 0.3.5 in /frontend ([#1260](https://github.com/hay-kot/mealie/issues/1260))
- Bump vue2-script-setup-transform in /frontend ([#1263](https://github.com/hay-kot/mealie/issues/1263))
- Update dev dependencies ([#1282](https://github.com/hay-kot/mealie/issues/1282))
- Github stalebot changes ([#1271](https://github.com/mealie-recipes/mealie/issues/1271))
- Bump eslint-plugin-nuxt in /frontend ([#1258](https://github.com/mealie-recipes/mealie/issues/1258))
- Bump @vue/runtime-dom in /frontend ([#1259](https://github.com/mealie-recipes/mealie/issues/1259))
- Bump nuxt-vite from 0.1.3 to 0.3.5 in /frontend ([#1260](https://github.com/mealie-recipes/mealie/issues/1260))
- Bump vue2-script-setup-transform in /frontend ([#1263](https://github.com/mealie-recipes/mealie/issues/1263))
- Update dev dependencies ([#1282](https://github.com/mealie-recipes/mealie/issues/1282))
### Refactor
- Split up recipe create page ([#1283](https://github.com/hay-kot/mealie/issues/1283))
- Split up recipe create page ([#1283](https://github.com/mealie-recipes/mealie/issues/1283))

View File

@ -1,36 +1,36 @@
### Bug Fixes
- Update issue links in v1.0.0beta-2 changelog ([#1312](https://github.com/hay-kot/mealie/issues/1312))
- Bad import path ([#1313](https://github.com/hay-kot/mealie/issues/1313))
- Printer page refs ([#1314](https://github.com/hay-kot/mealie/issues/1314))
- Update issue links in v1.0.0beta-2 changelog ([#1312](https://github.com/mealie-recipes/mealie/issues/1312))
- Bad import path ([#1313](https://github.com/mealie-recipes/mealie/issues/1313))
- Printer page refs ([#1314](https://github.com/mealie-recipes/mealie/issues/1314))
- Consolidate stores to fix mismatched state
- Bump @vue/composition-api from 1.6.1 to 1.6.2 in /frontend ([#1275](https://github.com/hay-kot/mealie/issues/1275))
- Shopping list label editor ([#1333](https://github.com/hay-kot/mealie/issues/1333))
- Bump @vue/composition-api from 1.6.1 to 1.6.2 in /frontend ([#1275](https://github.com/mealie-recipes/mealie/issues/1275))
- Shopping list label editor ([#1333](https://github.com/mealie-recipes/mealie/issues/1333))
### Features
- Default unit fractions to True
- Add unit abbreviation support ([#1332](https://github.com/hay-kot/mealie/issues/1332))
- Attached images by drag and drop for recipe steps ([#1341](https://github.com/hay-kot/mealie/issues/1341))
- Add unit abbreviation support ([#1332](https://github.com/mealie-recipes/mealie/issues/1332))
- Attached images by drag and drop for recipe steps ([#1341](https://github.com/mealie-recipes/mealie/issues/1341))
### Docs
- Render homepage social media link images at 32x32 size ([#1310](https://github.com/hay-kot/mealie/issues/1310))
- Render homepage social media link images at 32x32 size ([#1310](https://github.com/mealie-recipes/mealie/issues/1310))
### Miscellaneous Tasks
- Init git-cliff config
- Bump @types/sortablejs in /frontend ([#1287](https://github.com/hay-kot/mealie/issues/1287))
- Bump @babel/eslint-parser in /frontend ([#1290](https://github.com/hay-kot/mealie/issues/1290))
- Bump @types/sortablejs in /frontend ([#1287](https://github.com/mealie-recipes/mealie/issues/1287))
- Bump @babel/eslint-parser in /frontend ([#1290](https://github.com/mealie-recipes/mealie/issues/1290))
### Refactor
- Unify recipe-organizer components ([#1340](https://github.com/hay-kot/mealie/issues/1340))
- Unify recipe-organizer components ([#1340](https://github.com/mealie-recipes/mealie/issues/1340))
### Security
- Delay server response whenever username is non existing ([#1338](https://github.com/hay-kot/mealie/issues/1338))
- Delay server response whenever username is non existing ([#1338](https://github.com/mealie-recipes/mealie/issues/1338))
### Wip
- Pagination-repository ([#1316](https://github.com/hay-kot/mealie/issues/1316))
- Pagination-repository ([#1316](https://github.com/mealie-recipes/mealie/issues/1316))

View File

@ -63,57 +63,57 @@ If either of the above actions prevent the user from uploading images, the appli
### Bug Fixes
- For erroneously-translated datetime config ([#1362](https://github.com/hay-kot/mealie/issues/1362))
- Fixed text color on RecipeCard in RecipePrintView and implemented ingredient sections ([#1351](https://github.com/hay-kot/mealie/issues/1351))
- Ingredient sections lost after parsing ([#1368](https://github.com/hay-kot/mealie/issues/1368))
- Increased float rounding precision for CRF parser ([#1369](https://github.com/hay-kot/mealie/issues/1369))
- Infinite scroll bug on all recipes page ([#1393](https://github.com/hay-kot/mealie/issues/1393))
- Fast fail of bulk importer ([#1394](https://github.com/hay-kot/mealie/issues/1394))
- Bump @mdi/js from 5.9.55 to 6.7.96 in /frontend ([#1279](https://github.com/hay-kot/mealie/issues/1279))
- Bump @nuxtjs/i18n from 7.0.3 to 7.2.2 in /frontend ([#1288](https://github.com/hay-kot/mealie/issues/1288))
- Bump date-fns from 2.23.0 to 2.28.0 in /frontend ([#1293](https://github.com/hay-kot/mealie/issues/1293))
- Bump fuse.js from 6.5.3 to 6.6.2 in /frontend ([#1325](https://github.com/hay-kot/mealie/issues/1325))
- Bump core-js from 3.17.2 to 3.23.1 in /frontend ([#1383](https://github.com/hay-kot/mealie/issues/1383))
- All-recipes page now sorts alphabetically ([#1405](https://github.com/hay-kot/mealie/issues/1405))
- Sort recent recipes by created_at instead of date_added ([#1417](https://github.com/hay-kot/mealie/issues/1417))
- Only show scaler when ingredients amounts enabled ([#1426](https://github.com/hay-kot/mealie/issues/1426))
- Add missing types for API token deletion ([#1428](https://github.com/hay-kot/mealie/issues/1428))
- Entry nutrition checker ([#1448](https://github.com/hay-kot/mealie/issues/1448))
- Use == operator instead of is_ for sql queries ([#1453](https://github.com/hay-kot/mealie/issues/1453))
- Use `mtime` instead of `ctime` for backup dates ([#1461](https://github.com/hay-kot/mealie/issues/1461))
- Mealplan pagination ([#1464](https://github.com/hay-kot/mealie/issues/1464))
- Properly use pagination for group event notifies ([#1512](https://github.com/hay-kot/mealie/pull/1512))
- For erroneously-translated datetime config ([#1362](https://github.com/mealie-recipes/mealie/issues/1362))
- Fixed text color on RecipeCard in RecipePrintView and implemented ingredient sections ([#1351](https://github.com/mealie-recipes/mealie/issues/1351))
- Ingredient sections lost after parsing ([#1368](https://github.com/mealie-recipes/mealie/issues/1368))
- Increased float rounding precision for CRF parser ([#1369](https://github.com/mealie-recipes/mealie/issues/1369))
- Infinite scroll bug on all recipes page ([#1393](https://github.com/mealie-recipes/mealie/issues/1393))
- Fast fail of bulk importer ([#1394](https://github.com/mealie-recipes/mealie/issues/1394))
- Bump @mdi/js from 5.9.55 to 6.7.96 in /frontend ([#1279](https://github.com/mealie-recipes/mealie/issues/1279))
- Bump @nuxtjs/i18n from 7.0.3 to 7.2.2 in /frontend ([#1288](https://github.com/mealie-recipes/mealie/issues/1288))
- Bump date-fns from 2.23.0 to 2.28.0 in /frontend ([#1293](https://github.com/mealie-recipes/mealie/issues/1293))
- Bump fuse.js from 6.5.3 to 6.6.2 in /frontend ([#1325](https://github.com/mealie-recipes/mealie/issues/1325))
- Bump core-js from 3.17.2 to 3.23.1 in /frontend ([#1383](https://github.com/mealie-recipes/mealie/issues/1383))
- All-recipes page now sorts alphabetically ([#1405](https://github.com/mealie-recipes/mealie/issues/1405))
- Sort recent recipes by created_at instead of date_added ([#1417](https://github.com/mealie-recipes/mealie/issues/1417))
- Only show scaler when ingredients amounts enabled ([#1426](https://github.com/mealie-recipes/mealie/issues/1426))
- Add missing types for API token deletion ([#1428](https://github.com/mealie-recipes/mealie/issues/1428))
- Entry nutrition checker ([#1448](https://github.com/mealie-recipes/mealie/issues/1448))
- Use == operator instead of is_ for sql queries ([#1453](https://github.com/mealie-recipes/mealie/issues/1453))
- Use `mtime` instead of `ctime` for backup dates ([#1461](https://github.com/mealie-recipes/mealie/issues/1461))
- Mealplan pagination ([#1464](https://github.com/mealie-recipes/mealie/issues/1464))
- Properly use pagination for group event notifies ([#1512](https://github.com/mealie-recipes/mealie/pull/1512))
### Documentation
- Add go bulk import example ([#1388](https://github.com/hay-kot/mealie/issues/1388))
- Add go bulk import example ([#1388](https://github.com/mealie-recipes/mealie/issues/1388))
- Fix old link
- Pagination and filtering, and fixed a few broken links ([#1488](https://github.com/hay-kot/mealie/issues/1488))
- Pagination and filtering, and fixed a few broken links ([#1488](https://github.com/mealie-recipes/mealie/issues/1488))
### Features
- Toggle display of ingredient references in recipe instructions ([#1268](https://github.com/hay-kot/mealie/issues/1268))
- Add custom scaling option ([#1345](https://github.com/hay-kot/mealie/issues/1345))
- Implemented "order by" API parameters for recipe, food, and unit queries ([#1356](https://github.com/hay-kot/mealie/issues/1356))
- Implement user favorites page ([#1376](https://github.com/hay-kot/mealie/issues/1376))
- Extend Apprise JSON notification functionality with programmatic data ([#1355](https://github.com/hay-kot/mealie/issues/1355))
- Mealplan-webhooks ([#1403](https://github.com/hay-kot/mealie/issues/1403))
- Added "last-modified" header to supported record types ([#1379](https://github.com/hay-kot/mealie/issues/1379))
- Re-write get all routes to use pagination ([#1424](https://github.com/hay-kot/mealie/issues/1424))
- Advanced filtering API ([#1468](https://github.com/hay-kot/mealie/issues/1468))
- Restore frontend sorting for all recipes ([#1497](https://github.com/hay-kot/mealie/issues/1497))
- Implemented local storage for sorting and dynamic sort icons on the new recipe sort card ([1506](https://github.com/hay-kot/mealie/pull/1506))
- create new foods and units from their Data Management pages ([#1511](https://github.com/hay-kot/mealie/pull/1511))
- Toggle display of ingredient references in recipe instructions ([#1268](https://github.com/mealie-recipes/mealie/issues/1268))
- Add custom scaling option ([#1345](https://github.com/mealie-recipes/mealie/issues/1345))
- Implemented "order by" API parameters for recipe, food, and unit queries ([#1356](https://github.com/mealie-recipes/mealie/issues/1356))
- Implement user favorites page ([#1376](https://github.com/mealie-recipes/mealie/issues/1376))
- Extend Apprise JSON notification functionality with programmatic data ([#1355](https://github.com/mealie-recipes/mealie/issues/1355))
- Mealplan-webhooks ([#1403](https://github.com/mealie-recipes/mealie/issues/1403))
- Added "last-modified" header to supported record types ([#1379](https://github.com/mealie-recipes/mealie/issues/1379))
- Re-write get all routes to use pagination ([#1424](https://github.com/mealie-recipes/mealie/issues/1424))
- Advanced filtering API ([#1468](https://github.com/mealie-recipes/mealie/issues/1468))
- Restore frontend sorting for all recipes ([#1497](https://github.com/mealie-recipes/mealie/issues/1497))
- Implemented local storage for sorting and dynamic sort icons on the new recipe sort card ([1506](https://github.com/mealie-recipes/mealie/pull/1506))
- create new foods and units from their Data Management pages ([#1511](https://github.com/mealie-recipes/mealie/pull/1511))
### Miscellaneous Tasks
- Bump dev deps ([#1418](https://github.com/hay-kot/mealie/issues/1418))
- Bump @vue/runtime-dom in /frontend ([#1423](https://github.com/hay-kot/mealie/issues/1423))
- Backend page_all route cleanup ([#1483](https://github.com/hay-kot/mealie/issues/1483))
- Bump dev deps ([#1418](https://github.com/mealie-recipes/mealie/issues/1418))
- Bump @vue/runtime-dom in /frontend ([#1423](https://github.com/mealie-recipes/mealie/issues/1423))
- Backend page_all route cleanup ([#1483](https://github.com/mealie-recipes/mealie/issues/1483))
### Refactor
- Remove depreciated repo call ([#1370](https://github.com/hay-kot/mealie/issues/1370))
- Remove depreciated repo call ([#1370](https://github.com/mealie-recipes/mealie/issues/1370))
### Hotfix
@ -121,6 +121,6 @@ If either of the above actions prevent the user from uploading images, the appli
### UI
- Improve parser ui text display ([#1437](https://github.com/hay-kot/mealie/issues/1437))
- Improve parser ui text display ([#1437](https://github.com/mealie-recipes/mealie/issues/1437))
<!-- generated by git-cliff -->

View File

@ -20,8 +20,8 @@ Pull requests are the best way to propose changes to the codebase (we use [Githu
## Any contributions you make will be under the AGPL Software License
In short, when you submit code changes, your submissions are understood to be under the same [AGPL License](https://choosealicense.com/licenses/agpl-3.0/) that covers the project. Feel free to contact the maintainers if that's a concern.
## Report bugs using Github's [issues](https://github.com/hay-kot/mealie/issues)
We use GitHub issues to track public bugs. Report a bug by [opening a new issue](https://github.com/hay-kot/mealie/issues/new); it's that easy!
## Report bugs using Github's [issues](https://github.com/mealie-recipes/mealie/issues)
We use GitHub issues to track public bugs. Report a bug by [opening a new issue](https://github.com/mealie-recipes/mealie/issues/new); it's that easy!
## Write bug reports with detail, background, and sample code
**Great Bug Reports** tend to have:

View File

@ -124,9 +124,9 @@ docker-prod 🐳 Build and Start Docker Production Stack
```
## Internationalization
### Frontend
We use vue-i18n package for internationalization. Translations are stored in json format located in [frontend/lang/messages](https://github.com/hay-kot/mealie/tree/mealie-next/frontend/lang/messages).
We use vue-i18n package for internationalization. Translations are stored in json format located in [frontend/lang/messages](https://github.com/mealie-recipes/mealie/tree/mealie-next/frontend/lang/messages).
### Backend
Translations are stored in json format located in [mealie/lang/messages](https://github.com/hay-kot/mealie/tree/mealie-next/mealie/lang/messages).
Translations are stored in json format located in [mealie/lang/messages](https://github.com/mealie-recipes/mealie/tree/mealie-next/mealie/lang/messages).
### Quick frontend localization with VS Code
[i18n Ally for VScode](https://marketplace.visualstudio.com/items?itemName=lokalise.i18n-ally) is helpful for generating new strings to translate using Code Actions. It also has a nice feature, which shows translations in-place when editing code.

View File

@ -15,6 +15,6 @@ Alternatively, you can register a new parser by fulfilling the `ABCIngredientPar
## Links
- [Pretrained Model](https://github.com/hay-kot/mealie-nlp-model)
- [Pretrained Model](https://github.com/mealie-recipes/mealie-nlp-model)
- [CRF++ (Forked)](https://github.com/hay-kot/crfpp)

File diff suppressed because one or more lines are too long

View File

@ -330,9 +330,6 @@ export default defineComponent({
.list-group {
min-height: 38px;
}
.list-group-item {
cursor: move;
}
.list-group-item i {
cursor: pointer;
}

View File

@ -117,7 +117,7 @@
@click="toggleDisabled(index)"
>
<v-card-title :class="{ 'pb-0': !isChecked(index) }">
<span class="handle">
<span :class="isEditForm ? 'handle' : ''">
<v-icon v-if="isEditForm" size="26" class="pb-1">{{ $globals.icons.arrowUpDown }}</v-icon>
{{ $t("recipe.step-index", { step: index + 1 }) }}
</span>
@ -671,9 +671,6 @@ export default defineComponent({
.list-group {
min-height: 38px;
}
.list-group-item {
cursor: move;
}
.list-group-item i {
cursor: pointer;
}

View File

@ -114,6 +114,7 @@
"json": "JSON",
"keyword": "Sleutelwoord",
"link-copied": "Skakel gekopieer",
"loading": "Loading",
"loading-events": "Besig om gebeurtenisse te laai",
"loading-recipe": "Loading recipe...",
"loading-ocr-data": "Loading OCR data...",

View File

@ -114,6 +114,7 @@
"json": "JSON",
"keyword": "كلمة مفتاحية",
"link-copied": "تمّ نسْخ الرّابط",
"loading": "Loading",
"loading-events": "جاري تحميل الأحداث",
"loading-recipe": "Loading recipe...",
"loading-ocr-data": "Loading OCR data...",

View File

@ -114,6 +114,7 @@
"json": "JSON",
"keyword": "Ключова дума",
"link-copied": "Линкът е копиран",
"loading": "Loading",
"loading-events": "Зареждане на събития",
"loading-recipe": "Loading recipe...",
"loading-ocr-data": "Loading OCR data...",

View File

@ -114,6 +114,7 @@
"json": "JSON",
"keyword": "Paraula clau",
"link-copied": "S'ha copiat l'enllaç",
"loading": "Loading",
"loading-events": "Carregant esdeveniments",
"loading-recipe": "Carregant la recepta...",
"loading-ocr-data": "Carregant les dades OCR...",

View File

@ -114,6 +114,7 @@
"json": "JSON",
"keyword": "Klíčové slovo",
"link-copied": "Odkaz zkopírován",
"loading": "Loading",
"loading-events": "Načítání událostí",
"loading-recipe": "Loading recipe...",
"loading-ocr-data": "Loading OCR data...",

View File

@ -114,6 +114,7 @@
"json": "JSON",
"keyword": "Nøgleord",
"link-copied": "Link kopieret",
"loading": "Indlæser",
"loading-events": "Indlæser hændelser",
"loading-recipe": "Indlæser opskrift...",
"loading-ocr-data": "Indlæser OCR data...",

View File

@ -114,6 +114,7 @@
"json": "JSON",
"keyword": "Schlüsselwort",
"link-copied": "Link kopiert",
"loading": "Wird geladen...",
"loading-events": "Ereignisse werden geladen",
"loading-recipe": "Lade Rezept...",
"loading-ocr-data": "Lade OCR-Daten...",

View File

@ -114,6 +114,7 @@
"json": "JSON",
"keyword": "Λέξη-κλειδί",
"link-copied": "Ο Σύνδεσμος Αντιγράφηκε",
"loading": "Loading",
"loading-events": "Loading Events",
"loading-recipe": "Loading recipe...",
"loading-ocr-data": "Loading OCR data...",

View File

@ -114,6 +114,7 @@
"json": "JSON",
"keyword": "Keyword",
"link-copied": "Link Copied",
"loading": "Loading",
"loading-events": "Loading Events",
"loading-recipe": "Loading recipe...",
"loading-ocr-data": "Loading OCR data...",

View File

@ -114,6 +114,7 @@
"json": "JSON",
"keyword": "Keyword",
"link-copied": "Link Copied",
"loading": "Loading",
"loading-events": "Loading Events",
"loading-recipe": "Loading recipe...",
"loading-ocr-data": "Loading OCR data...",

View File

@ -114,6 +114,7 @@
"json": "JSON",
"keyword": "Etiqueta",
"link-copied": "Enlace copiado",
"loading": "Loading",
"loading-events": "Cargando Eventos",
"loading-recipe": "Loading recipe...",
"loading-ocr-data": "Loading OCR data...",

View File

@ -114,6 +114,7 @@
"json": "JSON",
"keyword": "Hakusana",
"link-copied": "Linkki kopioitu",
"loading": "Loading",
"loading-events": "Ladataan tapahtumia",
"loading-recipe": "Loading recipe...",
"loading-ocr-data": "Loading OCR data...",

View File

@ -114,6 +114,7 @@
"json": "JSON",
"keyword": "Mot-clé",
"link-copied": "Lien copié",
"loading": "Chargement",
"loading-events": "Chargement des événements",
"loading-recipe": "Chargement de la recette...",
"loading-ocr-data": "Chargement des données OCR...",
@ -875,7 +876,7 @@
"user-management": "Gestion des utilisateurs",
"reset-locked-users": "Réinitialiser les utilisateurs verrouillés",
"admin-user-creation": "Création d'un utilisateur admin",
"admin-user-management": "Admin User Management",
"admin-user-management": "Administration des utilisateurs",
"user-details": "Détails de l'utilisateur",
"user-name": "Nom d'utilisateur",
"authentication-method": "Méthode d'authentification",

View File

@ -114,6 +114,7 @@
"json": "JSON",
"keyword": "Mot-clé",
"link-copied": "Lien copié",
"loading": "Chargement",
"loading-events": "Chargement des événements",
"loading-recipe": "Chargement de la recette...",
"loading-ocr-data": "Chargement des données OCR...",

View File

@ -114,6 +114,7 @@
"json": "JSON",
"keyword": "Keyword",
"link-copied": "Link Copied",
"loading": "Loading",
"loading-events": "Loading Events",
"loading-recipe": "Loading recipe...",
"loading-ocr-data": "Loading OCR data...",

View File

@ -114,6 +114,7 @@
"json": "JSON",
"keyword": "מילת מפתח",
"link-copied": "קישור הועתק",
"loading": "Loading",
"loading-events": "טוען",
"loading-recipe": "Loading recipe...",
"loading-ocr-data": "Loading OCR data...",

View File

@ -114,6 +114,7 @@
"json": "JSON",
"keyword": "Ključna riječ",
"link-copied": "Poveznica kopirana",
"loading": "Loading",
"loading-events": "Učitavanje događaja",
"loading-recipe": "Loading recipe...",
"loading-ocr-data": "Loading OCR data...",

View File

@ -77,7 +77,7 @@
"tag-events": "Címke események",
"category-events": "Kategória események",
"when-a-new-user-joins-your-group": "Amikor egy új felhasználó csatlakozik a csoportodba",
"recipe-events": "Recipe Events"
"recipe-events": "Recept esemény"
},
"general": {
"cancel": "Mégsem",
@ -114,6 +114,7 @@
"json": "JSON",
"keyword": "Kulcsszó",
"link-copied": "Hivatkozás másolva",
"loading": "Loading",
"loading-events": "Események betöltése",
"loading-recipe": "Recept betöltése...",
"loading-ocr-data": "OCR adatok betöltése...",
@ -590,7 +591,7 @@
"import-summary": "Import összefoglaló",
"partial-backup": "Részleges biztonsági mentés",
"unable-to-delete-backup": "Nem lehetett létrehozni a biztonsági mentést.",
"experimental-description": "Backups a total snapshots of the database and data directory of the site. This includes all data and cannot be set to exclude subsets of data. You can think off this as a snapshot of Mealie at a specific time. Currently, {not-crossed-version} (data migrations are not done automatically). These serve as a database agnostic way to export and import data or backup the site to an external location.",
"experimental-description": "A biztonsági mentések az oldal adatbázisának és adatkönyvtárának teljes pillanatfelvételei. Ez az összes adatot tartalmazza, és nem lehet beállítani, hogy az adatok részhalmazait kizárja. Ezt úgy is elképzelheti, mint a Mealie egy adott időpontban készült pillanatfelvételét. Ezek adatbázis-független módon szolgálnak az adatok exportálására és importálására, vagy a webhely külső helyre történő mentésére.",
"backup-restore": "Biztonsági Mentés/Visszaállítás",
"back-restore-description": "A biztonsági mentés visszaállítása felülírja az adatbázisban és az adatkönyvtárban lévő összes aktuális adatot, és a biztonsági mentés tartalmával helyettesíti azokat. {cannot-be-undone} Ha a visszaállítás sikeres, akkor a rendszer kilépteti Önt.",
"cannot-be-undone": "Ezt a műveletet visszavonható - óvatosan használja.",
@ -1056,8 +1057,8 @@
"click": "Kattintson bármelyik mezőre a jobb oldalon, majd kattintson vissza a kép feletti téglalapra.",
"result": "A kiválasztott szöveg a korábban kiválasztott mezőben jelenik meg."
},
"pan-and-zoom-mode": "Pan and Zoom Mode",
"pan-and-zoom-desc": "Select pan and zoom by clicking the icon. This mode allows to zoom inside the image and move around to make using big images easier.",
"pan-and-zoom-mode": "Pásztázás és nagyítás mód",
"pan-and-zoom-desc": "Válassza ki a pásztázást és a nagyítást az ikonra kattintva. Ez a mód lehetővé teszi a kép nagyítását és mozgását a nagy képek használatának megkönnyítése érdekében.",
"split-text-mode": "Szöveg felosztási módok",
"split-modes": {
"line-mode": "Vonal mód (alapértelmezett)",
@ -1113,7 +1114,7 @@
"show-individual-confidence": "",
"ingredient-text": "Hozzávaló szöveg",
"average-confident": "{0} Confident",
"try-an-example": "Próbáld ki",
"try-an-example": "Próbáljon ki egy példát",
"parser": "Szintaxis elemző",
"background-tasks": "Háttér folyamatok",
"background-tasks-description": "Itt megtekintheti az összes futó háttérfeladatot és azok állapotát",

View File

@ -114,6 +114,7 @@
"json": "JSON",
"keyword": "Parola chiave",
"link-copied": "Link Copiato",
"loading": "Loading",
"loading-events": "Caricamento eventi",
"loading-recipe": "Loading recipe...",
"loading-ocr-data": "Loading OCR data...",

View File

@ -114,6 +114,7 @@
"json": "JSON",
"keyword": "キーワード",
"link-copied": "リンクをコピーしました。",
"loading": "Loading",
"loading-events": "Loading Events",
"loading-recipe": "Loading recipe...",
"loading-ocr-data": "Loading OCR data...",

View File

@ -114,6 +114,7 @@
"json": "JSON",
"keyword": "키워드",
"link-copied": "링크 복사됨",
"loading": "Loading",
"loading-events": "이벤트를 불러오는 중",
"loading-recipe": "Loading recipe...",
"loading-ocr-data": "Loading OCR data...",

View File

@ -114,6 +114,7 @@
"json": "JSON",
"keyword": "Raktažodis",
"link-copied": "Nuoroda nukopijuota",
"loading": "Loading",
"loading-events": "Užkrovimo įvykiai",
"loading-recipe": "Loading recipe...",
"loading-ocr-data": "Loading OCR data...",

View File

@ -114,6 +114,7 @@
"json": "JSON",
"keyword": "Keyword",
"link-copied": "Link Copied",
"loading": "Loading",
"loading-events": "Loading Events",
"loading-recipe": "Loading recipe...",
"loading-ocr-data": "Loading OCR data...",

View File

@ -114,6 +114,7 @@
"json": "JSON",
"keyword": "Trefwoord",
"link-copied": "Link Gekopieerd",
"loading": "Bezig met laden",
"loading-events": "Gebeurtenis laden",
"loading-recipe": "Recepten ophalen...",
"loading-ocr-data": "OCR gegevens laden...",

View File

@ -114,6 +114,7 @@
"json": "JSON",
"keyword": "Nøkkelord",
"link-copied": "Lenke kopiert",
"loading": "Loading",
"loading-events": "Laster hendelser",
"loading-recipe": "Laster oppskrift...",
"loading-ocr-data": "Laster OCR data...",

View File

@ -114,6 +114,7 @@
"json": "JSON",
"keyword": "Słowo kluczowe",
"link-copied": "Odnośnik skopiowany",
"loading": "Loading",
"loading-events": "Ładowanie wydarzeń",
"loading-recipe": "Loading recipe...",
"loading-ocr-data": "Loading OCR data...",

View File

@ -114,6 +114,7 @@
"json": "JSON",
"keyword": "Palavra chave",
"link-copied": "Link Copiado",
"loading": "Loading",
"loading-events": "Carregando eventos",
"loading-recipe": "Loading recipe...",
"loading-ocr-data": "Loading OCR data...",

View File

@ -114,6 +114,7 @@
"json": "JSON",
"keyword": "Palavra-chave",
"link-copied": "Ligação copiada",
"loading": "Loading",
"loading-events": "A carregar Eventos",
"loading-recipe": "A carregar receita...",
"loading-ocr-data": "A carregar dados OCR...",

View File

@ -114,6 +114,7 @@
"json": "JSON",
"keyword": "Cuvânt cheie",
"link-copied": "Link copiat",
"loading": "Loading",
"loading-events": "Se încarcă evenimentele",
"loading-recipe": "Loading recipe...",
"loading-ocr-data": "Loading OCR data...",

View File

@ -114,6 +114,7 @@
"json": "JSON",
"keyword": "Ключевое слово",
"link-copied": "Ссылка скопирована",
"loading": "Loading",
"loading-events": "Загрузка событий",
"loading-recipe": "Загрузка рецепта...",
"loading-ocr-data": "Загрузка данных OCR...",

View File

@ -114,6 +114,7 @@
"json": "JSON",
"keyword": "Kľučové slovo",
"link-copied": "Odkaz bol skopírovaný",
"loading": "Loading",
"loading-events": "Načítanie udalostí",
"loading-recipe": "Loading recipe...",
"loading-ocr-data": "Loading OCR data...",

View File

@ -114,6 +114,7 @@
"json": "JSON",
"keyword": "Ključna beseda",
"link-copied": "Povezava kopirana",
"loading": "Loading",
"loading-events": "Loading Events",
"loading-recipe": "Loading recipe...",
"loading-ocr-data": "Loading OCR data...",

View File

@ -114,6 +114,7 @@
"json": "JSON",
"keyword": "Ključna reč",
"link-copied": "Линк је копиран",
"loading": "Loading",
"loading-events": "Учитавање догађаја",
"loading-recipe": "Loading recipe...",
"loading-ocr-data": "Loading OCR data...",

View File

@ -114,6 +114,7 @@
"json": "JSON",
"keyword": "Nyckelord",
"link-copied": "Länk kopierad",
"loading": "Loading",
"loading-events": "Laddar händelser",
"loading-recipe": "Loading recipe...",
"loading-ocr-data": "Loading OCR data...",

View File

@ -114,6 +114,7 @@
"json": "JSON",
"keyword": "Anahtar Kelime",
"link-copied": "Bağlantı Kopyalandı",
"loading": "Loading",
"loading-events": "Etkinlikler yükleniyor",
"loading-recipe": "Loading recipe...",
"loading-ocr-data": "OCR verileri yükleniyor...",

View File

@ -114,6 +114,7 @@
"json": "JSON",
"keyword": "Ключове слово",
"link-copied": "Посилання скопійовано",
"loading": "Завантаження",
"loading-events": "Завантаження подій",
"loading-recipe": "Завантаження рецепта...",
"loading-ocr-data": "Завантаження даних OCR...",

View File

@ -114,6 +114,7 @@
"json": "JSON",
"keyword": "Keyword",
"link-copied": "Link Copied",
"loading": "Loading",
"loading-events": "Loading Events",
"loading-recipe": "Loading recipe...",
"loading-ocr-data": "Loading OCR data...",

View File

@ -114,6 +114,7 @@
"json": "JSON",
"keyword": "关键字",
"link-copied": "链接已复制",
"loading": "Loading",
"loading-events": "正在加载事件",
"loading-recipe": "Loading recipe...",
"loading-ocr-data": "Loading OCR data...",

View File

@ -114,6 +114,7 @@
"json": "JSON",
"keyword": "關鍵字",
"link-copied": "已複製連結",
"loading": "Loading",
"loading-events": "Loading Events",
"loading-recipe": "Loading recipe...",
"loading-ocr-data": "Loading OCR data...",

View File

@ -1,137 +0,0 @@
<template>
<v-container fluid class="md-container">
<BannerExperimental></BannerExperimental>
<BaseCardSectionTitle title="Site Analytics">
Your instance of Mealie can send anonymous usage statistics to the Mealie project team. This is done to help us
gauge the usage of mealie, provide public statistics and to help us improve the user experience.
<p class="pt-4 pb-0 mb-0">
Your installation creates a UUID that is used to identify your installation,
<strong> this is randomly generated using the UUID4 implementation in python</strong>. This UUID is stored on
our analytics server and used to ensure your data is only counted once.
</p>
</BaseCardSectionTitle>
<section>
<BaseCardSectionTitle class="pb-0" :icon="$globals.icons.chart" title="Analytics Settings">
When you opt into analytics your install will register itself with the Analytics API to count the installation
and register your generated anonymous installation ID
</BaseCardSectionTitle>
<v-card-text>
<v-switch v-model="state.analyticsEnabled" label="Collect Anonymous Analytics" />
</v-card-text>
</section>
<section class="my-8">
<BaseCardSectionTitle class="pb-0" :icon="$globals.icons.chart" title="Analytics Data">
This is a list of all the data that is sent to the Mealie project team.
</BaseCardSectionTitle>
<v-card class="ma-2">
<template v-for="(value, idx) in data">
<v-list-item :key="`item-${idx}`">
<v-list-item-title class="py-2">
<div>{{ value.text }}</div>
<v-list-item-subtitle class="text-end"> {{ getValue(value.valueKey) }} </v-list-item-subtitle>
</v-list-item-title>
</v-list-item>
<v-divider :key="`divider-${idx}`" class="mx-2"></v-divider>
</template>
</v-card>
</section>
</v-container>
</template>
<script lang="ts">
import { defineComponent, reactive, useAsync } from "@nuxtjs/composition-api";
import { useAdminApi } from "~/composables/api";
import { useAsyncKey } from "~/composables/use-utils";
import { MealieAnalytics } from "~/lib/api/types/analytics";
type DisplayData = {
text: string;
valueKey: keyof MealieAnalytics;
};
export default defineComponent({
layout: "admin",
setup() {
const adminApi = useAdminApi();
const state = reactive({
analyticsEnabled: false,
});
const analyticsData = useAsync(async () => {
const { data } = await adminApi.analytics.getAnalytics();
return data;
}, useAsyncKey());
function getValue(key: keyof MealieAnalytics) {
if (!analyticsData.value) {
return "";
}
return analyticsData.value[key];
}
const data: DisplayData[] = [
{
text: "Installation Id",
valueKey: "installationId",
},
{
text: "Version",
valueKey: "version",
},
{
text: "Database",
valueKey: "databaseType",
},
{
text: "Using Email",
valueKey: "usingEmail",
},
{
text: "Using LDAP",
valueKey: "usingLdap",
},
{
text: "API Tokens",
valueKey: "apiTokens",
},
{
text: "Users",
valueKey: "users",
},
{
text: "Recipes",
valueKey: "recipes",
},
{
text: "Groups",
valueKey: "groups",
},
{
text: "Shopping Lists",
valueKey: "shoppingLists",
},
{
text: "Cookbooks",
valueKey: "cookbooks",
},
];
return {
data,
state,
analyticsData,
getValue,
};
},
head() {
return {
title: "Analytics",
};
},
});
</script>
<style scoped></style>

View File

@ -1,5 +1,6 @@
<template>
<v-container fluid class="narrow-container">
<!-- Image -->
<BasePageTitle divider>
<template #header>
<v-img max-height="200" max-width="150" :src="require('~/static/svgs/admin-site-settings.svg')"></v-img>
@ -7,6 +8,7 @@
<template #title> {{ $t("settings.site-settings") }} </template>
</BasePageTitle>
<!-- Bug Report -->
<BaseDialog v-model="bugReportDialog" :title="$t('settings.bug-report')" :width="800" :icon="$globals.icons.github">
<v-card-text>
<div class="pb-4">
@ -27,7 +29,6 @@
<BaseButton
color="info"
@click="
dockerValidate();
bugReportDialog = true;
"
>
@ -36,6 +37,7 @@
</BaseButton>
</div>
<!-- Configuration -->
<section>
<BaseCardSectionTitle class="pb-0" :icon="$globals.icons.cog" :title="$tc('settings.configuration')"> </BaseCardSectionTitle>
<v-card class="mb-4">
@ -60,40 +62,7 @@
</v-card>
</section>
<section>
<BaseCardSectionTitle class="pt-2" :icon="$globals.icons.docker" :title="$tc('settings.docker-volume')" />
<v-alert
border="left"
colored-border
:type="docker.state === DockerVolumeState.Error ? 'error' : 'info'"
:icon="$globals.icons.docker"
elevation="2"
:loading="docker.loading"
>
<div class="d-flex align-center font-weight-medium">
{{ $t('settings.docker-volume') }}
<HelpIcon small class="my-n3">
{{ $t('settings.docker-volume-help') }}
</HelpIcon>
</div>
<div>
<template v-if="docker.state === DockerVolumeState.Error"> {{ $t('settings.volumes-are-misconfigured') }} </template>
<template v-else-if="docker.state === DockerVolumeState.Success">
{{ $t('settings.volumes-are-configured-correctly') }}
</template>
<template v-else-if="docker.state === DockerVolumeState.Unknown">
{{ $t('settings.status-unknown-try-running-a-validation') }}
</template>
</div>
<div class="mt-4">
<BaseButton color="info" :loading="docker.loading" @click="dockerValidate">
<template #icon> {{ $globals.icons.checkboxMarkedCircle }} </template>
{{ $t('settings.validate') }}
</BaseButton>
</div>
</v-alert>
</section>
<!-- Email -->
<section>
<BaseCardSectionTitle class="pt-2" :icon="$globals.icons.email" :title="$tc('user.email')" />
<v-alert border="left" colored-border :type="appConfig.emailReady ? 'success' : 'error'" elevation="2">
@ -130,40 +99,47 @@
<section class="mt-4">
<BaseCardSectionTitle class="pb-0" :icon="$globals.icons.cog" :title="$tc('settings.general-about')"> </BaseCardSectionTitle>
<v-card class="mb-4">
<template v-for="(property, idx) in appInfo">
<v-list-item :key="property.name">
<v-list-item-icon>
<v-icon> {{ property.icon || $globals.icons.user }} </v-icon>
</v-list-item-icon>
<v-list-item-content>
<v-list-item-title>
<div>{{ property.name }}</div>
</v-list-item-title>
<template v-if="property.slot === 'recipe-scraper'">
<v-list-item-subtitle>
<a
target="_blank"
:href="`https://github.com/hhursev/recipe-scrapers/releases/tag/${property.value}`"
>
<template v-if="appInfo && appInfo.length">
<template v-for="(property, idx) in appInfo">
<v-list-item :key="property.name">
<v-list-item-icon>
<v-icon> {{ property.icon || $globals.icons.user }} </v-icon>
</v-list-item-icon>
<v-list-item-content>
<v-list-item-title>
<div>{{ property.name }}</div>
</v-list-item-title>
<template v-if="property.slot === 'recipe-scraper'">
<v-list-item-subtitle>
<a
target="_blank"
:href="`https://github.com/hhursev/recipe-scrapers/releases/tag/${property.value}`"
>
{{ property.value }}
</a>
</v-list-item-subtitle>
</template>
<template v-else-if="property.slot === 'build'">
<v-list-item-subtitle>
<a target="_blank" :href="`https://github.com/hay-kot/mealie/commit/${property.value}`">
{{ property.value }}
</a>
</v-list-item-subtitle>
</template>
<template v-else>
<v-list-item-subtitle>
{{ property.value }}
</a>
</v-list-item-subtitle>
</template>
<template v-else-if="property.slot === 'build'">
<v-list-item-subtitle>
<a target="_blank" :href="`https://github.com/hay-kot/mealie/commit/${property.value}`">
{{ property.value }}
</a>
</v-list-item-subtitle>
</template>
<template v-else>
<v-list-item-subtitle>
{{ property.value }}
</v-list-item-subtitle>
</template>
</v-list-item-content>
</v-list-item>
<v-divider v-if="appInfo && idx !== appInfo.length - 1" :key="`divider-${property.name}`"></v-divider>
</v-list-item-subtitle>
</template>
</v-list-item-content>
</v-list-item>
<v-divider v-if="appInfo && idx !== appInfo.length - 1" :key="`divider-${property.name}`"></v-divider>
</template>
</template>
<template v-else>
<div class="mb-3 text-center">
<AppLoader :waiting-text="$tc('general.loading')" />
</div>
</template>
</v-card>
</section>
@ -186,6 +162,7 @@ import { useAdminApi, useUserApi } from "~/composables/api";
import { validators } from "~/composables/use-validators";
import { useAsyncKey } from "~/composables/use-utils";
import { CheckAppConfig } from "~/lib/api/types/admin";
import AppLoader from "~/components/global/AppLoader.vue";
enum DockerVolumeState {
Unknown = "unknown",
@ -208,294 +185,230 @@ interface CheckApp extends CheckAppConfig {
}
export default defineComponent({
layout: "admin",
setup() {
// ==========================================================
// Docker Volume Validation
const docker = reactive({
loading: false,
state: DockerVolumeState.Unknown,
});
async function dockerValidate() {
docker.loading = true;
// Do API Check
const { data } = await adminApi.about.checkDocker();
if (data == null) {
docker.state = DockerVolumeState.Error;
return;
}
// Get File Contents
const { data: fileContents } = await adminApi.about.getDockerValidateFileContents();
if (data.text === fileContents) {
docker.state = DockerVolumeState.Success;
} else {
docker.state = DockerVolumeState.Error;
}
docker.loading = false;
}
const state = reactive({
loading: false,
address: "",
success: false,
error: "",
tested: false,
});
const appConfig = ref<CheckApp>({
emailReady: true,
baseUrlSet: true,
isSiteSecure: true,
isUpToDate: false,
ldapReady: false,
});
function isLocalHostOrHttps() {
return window.location.hostname === "localhost" || window.location.protocol === "https:";
}
const api = useUserApi();
const adminApi = useAdminApi();
onMounted(async () => {
const { data } = await adminApi.about.checkApp();
if (data) {
appConfig.value = { ...data, isSiteSecure: false };
}
appConfig.value.isSiteSecure = isLocalHostOrHttps();
});
const simpleChecks = computed<SimpleCheck[]>(() => {
const goodIcon = $globals.icons.checkboxMarkedCircle;
const badIcon = $globals.icons.alert;
const warningIcon = $globals.icons.alertCircle;
const goodColor = "success";
const badColor = "error";
const warningColor = "warning";
const data: SimpleCheck[] = [
{
id: "application-version",
text: i18n.t("settings.application-version"),
status: appConfig.value.isUpToDate,
errorText: i18n.t("settings.application-version-error-text", [rawAppInfo.value.version, rawAppInfo.value.versionLatest]),
successText: i18n.t("settings.mealie-is-up-to-date"),
color: appConfig.value.isUpToDate ? goodColor : warningColor,
icon: appConfig.value.isUpToDate ? goodIcon : warningIcon,
},
{
id: "secure-site",
text: i18n.t("settings.secure-site"),
status: appConfig.value.isSiteSecure,
errorText: i18n.t("settings.secure-site-error-text"),
successText: i18n.t("settings.secure-site-success-text"),
color: appConfig.value.isSiteSecure ? goodColor : badColor,
icon: appConfig.value.isSiteSecure ? goodIcon : badIcon,
},
{
id: "server-side-base-url",
text: i18n.t("settings.server-side-base-url"),
status: appConfig.value.baseUrlSet,
errorText:
i18n.t("settings.server-side-base-url-error-text"),
successText: i18n.t("settings.server-side-base-url-success-text"),
color: appConfig.value.baseUrlSet ? goodColor : badColor,
icon: appConfig.value.baseUrlSet ? goodIcon : badIcon,
},
{
id: "ldap-ready",
text: i18n.t("settings.ldap-ready"),
status: appConfig.value.ldapReady,
errorText:
i18n.t("settings.ldap-ready-error-text"),
successText: i18n.t("settings.ldap-ready-success-text"),
color: appConfig.value.ldapReady ? goodColor : warningColor,
icon: appConfig.value.ldapReady ? goodIcon : warningIcon,
},
];
return data;
});
async function testEmail() {
state.loading = true;
state.tested = false;
const { data } = await api.email.test({ email: state.address });
if (data) {
if (data.success) {
state.success = true;
} else {
state.error = data.error ?? "";
state.success = false;
components: { AppLoader },
layout: "admin",
setup() {
const state = reactive({
loading: false,
address: "",
success: false,
error: "",
tested: false,
});
const appConfig = ref<CheckApp>({
emailReady: true,
baseUrlSet: true,
isSiteSecure: true,
isUpToDate: false,
ldapReady: false,
});
function isLocalHostOrHttps() {
return window.location.hostname === "localhost" || window.location.protocol === "https:";
}
}
state.loading = false;
state.tested = true;
const api = useUserApi();
const adminApi = useAdminApi();
onMounted(async () => {
const { data } = await adminApi.about.checkApp();
if (data) {
appConfig.value = { ...data, isSiteSecure: false };
}
appConfig.value.isSiteSecure = isLocalHostOrHttps();
});
const simpleChecks = computed<SimpleCheck[]>(() => {
const goodIcon = $globals.icons.checkboxMarkedCircle;
const badIcon = $globals.icons.alert;
const warningIcon = $globals.icons.alertCircle;
const goodColor = "success";
const badColor = "error";
const warningColor = "warning";
const data: SimpleCheck[] = [
{
id: "application-version",
text: i18n.t("settings.application-version"),
status: appConfig.value.isUpToDate,
errorText: i18n.t("settings.application-version-error-text", [rawAppInfo.value.version, rawAppInfo.value.versionLatest]),
successText: i18n.t("settings.mealie-is-up-to-date"),
color: appConfig.value.isUpToDate ? goodColor : warningColor,
icon: appConfig.value.isUpToDate ? goodIcon : warningIcon,
},
{
id: "secure-site",
text: i18n.t("settings.secure-site"),
status: appConfig.value.isSiteSecure,
errorText: i18n.t("settings.secure-site-error-text"),
successText: i18n.t("settings.secure-site-success-text"),
color: appConfig.value.isSiteSecure ? goodColor : badColor,
icon: appConfig.value.isSiteSecure ? goodIcon : badIcon,
},
{
id: "server-side-base-url",
text: i18n.t("settings.server-side-base-url"),
status: appConfig.value.baseUrlSet,
errorText: i18n.t("settings.server-side-base-url-error-text"),
successText: i18n.t("settings.server-side-base-url-success-text"),
color: appConfig.value.baseUrlSet ? goodColor : badColor,
icon: appConfig.value.baseUrlSet ? goodIcon : badIcon,
},
{
id: "ldap-ready",
text: i18n.t("settings.ldap-ready"),
status: appConfig.value.ldapReady,
errorText: i18n.t("settings.ldap-ready-error-text"),
successText: i18n.t("settings.ldap-ready-success-text"),
color: appConfig.value.ldapReady ? goodColor : warningColor,
icon: appConfig.value.ldapReady ? goodIcon : warningIcon,
},
];
return data;
});
async function testEmail() {
state.loading = true;
state.tested = false;
const { data } = await api.email.test({ email: state.address });
if (data) {
if (data.success) {
state.success = true;
}
else {
state.error = data.error ?? "";
state.success = false;
}
}
state.loading = false;
state.tested = true;
}
const validEmail = computed(() => {
if (state.address === "") {
return false;
}
const valid = validators.email(state.address);
// Explicit bool check because validators.email sometimes returns a string
if (valid === true) {
return true;
}
return false;
});
// ============================================================
// General About Info
const { $globals, i18n } = useContext();
const rawAppInfo = ref({
version: "null",
versionLatest: "null",
});
function getAppInfo() {
const statistics = useAsync(async () => {
const { data } = await adminApi.about.about();
if (data) {
rawAppInfo.value.version = data.version;
rawAppInfo.value.versionLatest = data.versionLatest;
const prettyInfo = [
{
name: i18n.t("about.version"),
icon: $globals.icons.information,
value: data.version,
},
{
slot: "build",
name: i18n.t("settings.build"),
icon: $globals.icons.information,
value: data.buildId,
},
{
name: i18n.t("about.application-mode"),
icon: $globals.icons.devTo,
value: data.production ? i18n.t("about.production") : i18n.t("about.development"),
},
{
name: i18n.t("about.demo-status"),
icon: $globals.icons.testTube,
value: data.demoStatus ? i18n.t("about.demo") : i18n.t("about.not-demo"),
},
{
name: i18n.t("about.api-port"),
icon: $globals.icons.api,
value: data.apiPort,
},
{
name: i18n.t("about.api-docs"),
icon: $globals.icons.file,
value: data.apiDocs ? i18n.t("general.enabled") : i18n.t("general.disabled"),
},
{
name: i18n.t("about.database-type"),
icon: $globals.icons.database,
value: data.dbType,
},
{
name: i18n.t("about.database-url"),
icon: $globals.icons.database,
value: data.dbUrl,
},
{
name: i18n.t("about.default-group"),
icon: $globals.icons.group,
value: data.defaultGroup,
},
{
slot: "recipe-scraper",
name: i18n.t("settings.recipe-scraper-version"),
icon: $globals.icons.primary,
value: data.recipeScraperVersion,
},
];
return prettyInfo;
}
return data;
}, useAsyncKey());
return statistics;
}
const appInfo = getAppInfo();
const bugReportDialog = ref(false);
const bugReportText = computed(() => {
const ignore = {
[i18n.tc("about.database-url")]: true,
[i18n.tc("about.default-group")]: true,
};
let text = "**Details**\n";
appInfo.value?.forEach((item) => {
if (ignore[item.name as string]) {
return;
}
text += `${item.name as string}: ${item.value as string}\n`;
});
const ignoreChecks: {
[key: string]: boolean;
} = {
"application-version": true,
};
text += "\n**Checks**\n";
simpleChecks.value.forEach((item) => {
if (ignoreChecks[item.id]) {
return;
}
const status = item.status ? i18n.tc("general.yes") : i18n.tc("general.no");
text += `${item.text.toString()}: ${status}\n`;
});
text += `${i18n.tc("settings.email-configured")}: ${appConfig.value.emailReady ? i18n.tc("general.yes") : i18n.tc("general.no")}\n`;
return text;
});
return {
bugReportDialog,
bugReportText,
DockerVolumeState,
simpleChecks,
appConfig,
validEmail,
validators,
...toRefs(state),
testEmail,
appInfo,
};
},
head() {
return {
title: this.$t("settings.site-settings") as string,
};
}
const validEmail = computed(() => {
if (state.address === "") {
return false;
}
const valid = validators.email(state.address);
// Explicit bool check because validators.email sometimes returns a string
if (valid === true) {
return true;
}
return false;
});
// ============================================================
// General About Info
const { $globals, i18n } = useContext();
const rawAppInfo = ref({
version: "null",
versionLatest: "null",
});
function getAppInfo() {
const statistics = useAsync(async () => {
const { data } = await adminApi.about.about();
if (data) {
rawAppInfo.value.version = data.version;
rawAppInfo.value.versionLatest = data.versionLatest;
const prettyInfo = [
{
name: i18n.t("about.version"),
icon: $globals.icons.information,
value: data.version,
},
{
slot: "build",
name: i18n.t("settings.build"),
icon: $globals.icons.information,
value: data.buildId,
},
{
name: i18n.t("about.application-mode"),
icon: $globals.icons.devTo,
value: data.production ? i18n.t("about.production") : i18n.t("about.development"),
},
{
name: i18n.t("about.demo-status"),
icon: $globals.icons.testTube,
value: data.demoStatus ? i18n.t("about.demo") : i18n.t("about.not-demo"),
},
{
name: i18n.t("about.api-port"),
icon: $globals.icons.api,
value: data.apiPort,
},
{
name: i18n.t("about.api-docs"),
icon: $globals.icons.file,
value: data.apiDocs ? i18n.t("general.enabled") : i18n.t("general.disabled"),
},
{
name: i18n.t("about.database-type"),
icon: $globals.icons.database,
value: data.dbType,
},
{
name: i18n.t("about.database-url"),
icon: $globals.icons.database,
value: data.dbUrl,
},
{
name: i18n.t("about.default-group"),
icon: $globals.icons.group,
value: data.defaultGroup,
},
{
slot: "recipe-scraper",
name: i18n.t("settings.recipe-scraper-version"),
icon: $globals.icons.primary,
value: data.recipeScraperVersion,
},
];
return prettyInfo;
}
return data;
}, useAsyncKey());
return statistics;
}
const appInfo = getAppInfo();
const bugReportDialog = ref(false);
const bugReportText = computed(() => {
const ignore = {
[i18n.tc("about.database-url")]: true,
[i18n.tc("about.default-group")]: true,
};
let text = "**Details**\n";
appInfo.value?.forEach((item) => {
if (ignore[item.name as string]) {
return;
}
text += `${item.name as string}: ${item.value as string}\n`;
});
const ignoreChecks: { [key: string]: boolean } = {
"application-version": true,
};
text += "\n**Checks**\n";
simpleChecks.value.forEach((item) => {
if (ignoreChecks[item.id]) {
return;
}
const status = item.status ? i18n.tc("general.yes") : i18n.tc("general.no");
text += `${item.text.toString()}: ${status}\n`;
});
text += `${i18n.tc("settings.email-configured")}: ${appConfig.value.emailReady ? i18n.tc("general.yes") : i18n.tc("general.no")}\n`;
text += `${i18n.tc("settings.docker-volume")}: ${docker.state}`;
return text;
});
return {
bugReportDialog,
bugReportText,
DockerVolumeState,
docker,
dockerValidate,
simpleChecks,
appConfig,
validEmail,
validators,
...toRefs(state),
testEmail,
appInfo,
};
},
head() {
return {
title: this.$t("settings.site-settings") as string,
};
},
});
</script>

View File

@ -103,7 +103,11 @@ export default defineComponent({
if (refreshTags) {
tags.actions.refresh();
}
router.push(`/g/${groupSlug.value}/r/${response.data}?edit=${edit.toString()}`);
// we clear the query params first so if the user hits back, they don't re-import the recipe
router.replace({ query: {} }).then(
() => router.push(`/g/${groupSlug.value}/r/${response.data}?edit=${edit.toString()}`)
);
}
const recipeUrl = computed({

View File

@ -6,7 +6,6 @@
</template>
<template #title> {{ $t('data-pages.data-management') }} </template>
{{ $t('data-pages.data-management-description') }}
<BannerExperimental class="mt-5"></BannerExperimental>
<template #content>
<div>
<BaseOverflowButton

View File

@ -24,8 +24,8 @@
</v-date-picker>
</v-menu>
<div class="d-flex align-center justify-space-between mb-2">
<v-tabs>
<div class="d-flex flex-wrap align-center justify-space-between mb-2">
<v-tabs style="width: fit-content;">
<v-tab :to="`/group/mealplan/planner/view`">{{ $t('meal-plan.meal-planner') }}</v-tab>
<v-tab :to="`/group/mealplan/planner/edit`">{{ $t('general.edit') }}</v-tab>
</v-tabs>

View File

@ -0,0 +1,50 @@
from slugify import slugify
from sqlalchemy.exc import IntegrityError
from sqlalchemy.orm import Session
from mealie.core import root_logger
from mealie.db.models.group import Group
logger = root_logger.get_logger("init_db")
def _do_fix(session: Session, group: Group, counter: int):
if counter:
new_name = f"{group.id} ({counter})"
else:
new_name = str(group.id)
group.name = new_name
group.slug = slugify(group.name)
session.commit()
def fix_group_with_no_name(session: Session):
groups = session.query(Group).filter(Group.name == "").all()
if not groups:
logger.debug("No group found with an empty name; skipping fix")
return
logger.info(
f'{len(groups)} {"group" if len(groups) == 1 else "groups"} found with a missing name; '
f"applying default name"
)
offset = 0
for i, group in enumerate(groups):
attempts = 0
while True:
if attempts >= 3:
raise Exception(
f'Unable to fix empty group name for group_id "{group.id}": too many attempts ({attempts})'
)
counter = i + offset
try:
_do_fix(session, group, counter)
break
except IntegrityError:
session.rollback()
attempts += 1
offset += 1
continue

View File

@ -13,7 +13,7 @@ def fix_slug_food_names(db: AllRepositories):
logger = root_logger.get_logger("init_db")
if not food:
logger.info(f"No food found with slug: '{check_for_food}' skipping fix")
logger.debug(f"No food found with slug: '{check_for_food}' skipping fix")
return
all_foods = db.ingredient_foods.get_all()

View File

@ -10,6 +10,7 @@ from alembic.runtime import migration
from mealie.core import root_logger
from mealie.core.config import get_app_settings
from mealie.db.db_setup import session_context
from mealie.db.fixes.fix_group_with_no_name import fix_group_with_no_name
from mealie.db.fixes.fix_slug_foods import fix_slug_food_names
from mealie.repos.all_repositories import get_repositories
from mealie.repos.repository_factory import AllRepositories
@ -104,6 +105,7 @@ def main():
init_db(db)
safe_try(lambda: fix_slug_food_names(db))
safe_try(lambda: fix_group_with_no_name(session))
if __name__ == "__main__":

View File

@ -1,15 +1,10 @@
import asyncio
import random
import shutil
import string
from fastapi import APIRouter, BackgroundTasks
from fastapi import APIRouter
from recipe_scrapers import __version__ as recipe_scraper_version
from mealie.core.release_checker import get_latest_version
from mealie.core.settings.static import APP_VERSION
from mealie.routes._base import BaseAdminController, controller
from mealie.schema.admin.about import AdminAboutInfo, AppStatistics, CheckAppConfig, DockerVolumeText
from mealie.schema.admin.about import AdminAboutInfo, AppStatistics, CheckAppConfig
router = APIRouter(prefix="/about")
@ -57,25 +52,3 @@ class AdminAboutController(BaseAdminController):
base_url_set=settings.BASE_URL != "http://localhost:8080",
is_up_to_date=APP_VERSION == "develop" or APP_VERSION == "nightly" or get_latest_version() == APP_VERSION,
)
@router.get("/docker/validate", response_model=DockerVolumeText)
def validate_docker_volume(self, bg: BackgroundTasks):
validation_dir = self.folders.DATA_DIR / "docker-validation"
validation_dir.mkdir(exist_ok=True)
random_string = "".join(random.choice(string.ascii_uppercase + string.digits) for _ in range(100))
with validation_dir.joinpath("validate.txt").open("w") as f:
f.write(random_string)
async def cleanup():
await asyncio.sleep(60)
try:
shutil.rmtree(validation_dir)
except Exception as e:
self.logger.error(f"Failed to remove docker validation directory: {e}")
bg.add_task(cleanup)
return DockerVolumeText(text=random_string)

View File

@ -1,5 +1,5 @@
# This file is auto-generated by gen_schema_exports.py
from .about import AdminAboutInfo, AppInfo, AppStartupInfo, AppStatistics, AppTheme, CheckAppConfig, DockerVolumeText
from .about import AdminAboutInfo, AppInfo, AppStartupInfo, AppStatistics, AppTheme, CheckAppConfig
from .backup import AllBackups, BackupFile, BackupOptions, CreateBackup, ImportJob
from .email import EmailReady, EmailSuccess, EmailTest
from .maintenance import MaintenanceLogs, MaintenanceStorageDetails, MaintenanceSummary
@ -31,7 +31,6 @@ __all__ = [
"AppStatistics",
"AppTheme",
"CheckAppConfig",
"DockerVolumeText",
"EmailReady",
"EmailSuccess",
"EmailTest",

View File

@ -59,7 +59,3 @@ class CheckAppConfig(MealieModel):
ldap_ready: bool
base_url_set: bool
is_up_to_date: bool
class DockerVolumeText(MealieModel):
text: str

View File

@ -61,7 +61,7 @@ class ChangePassword(MealieModel):
class GroupBase(MealieModel):
name: str
name: constr(strip_whitespace=True, min_length=1) # type: ignore
class Config:
orm_mode = True

View File

@ -90,10 +90,10 @@ def clean_image(image: str | list | dict | None = None, default: str = "no image
image attempts to parse the image field from a recipe and return a string. Currenty
Supported Structures:
- `https://exmaple.com` - A string
- `{ "url": "https://exmaple.com" }` - A dictionary with a `url` key
- `["https://exmaple.com"]` - A list of strings
- `[{ "url": "https://exmaple.com" }]` - A list of dictionaries with a `url` key
- `https://example.com` - A string
- `{ "url": "https://example.com" }` - A dictionary with a `url` key
- `["https://example.com"]` - A list of strings
- `[{ "url": "https://example.com" }]` - A list of dictionaries with a `url` key
Raises:
TypeError: If the image field is not a supported type a TypeError is raised.
@ -113,8 +113,11 @@ def clean_image(image: str | list | dict | None = None, default: str = "no image
return [x["url"] for x in image]
case {"url": str(image)}:
return [image]
case [{"@id": str(_)}, *_]:
return [x["@id"] for x in image]
case _:
raise TypeError(f"Unexpected type for image: {type(image)}, {image}")
logger.exception(f"Unexpected type for image: {type(image)}, {image}")
return [default]
def clean_instructions(steps_object: list | dict | str, default: list | None = None) -> list[dict]:

View File

@ -212,10 +212,6 @@ class RecipeScraperPackage(ABCScraperStrategy):
class RecipeScraperOpenGraph(ABCScraperStrategy):
"""
Abstract class for all recipe parsers.
"""
async def get_html(self, url: str) -> str:
return await safe_scrape_html(url)
@ -245,7 +241,7 @@ class RecipeScraperOpenGraph(ABCScraperStrategy):
"recipeIngredient": ["Could not detect ingredients"],
"recipeInstructions": [{"text": "Could not detect instructions"}],
"slug": slugify(og_field(properties, "og:title")),
"orgURL": og_field(properties, "og:url"),
"orgURL": self.url,
"categories": [],
"tags": og_fields(properties, "og:article:tag"),
"dateAdded": None,