mirror of
https://github.com/mealie-recipes/mealie.git
synced 2026-06-02 23:20:26 -04:00
Compare commits
38 Commits
v3.19.0
...
chore/docs
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
845b2c2c73 | ||
|
|
15b3e59c55 | ||
|
|
0af9633193 | ||
|
|
b5987f5a46 | ||
|
|
e24187fefb | ||
|
|
396fcd5ee4 | ||
|
|
5a3d202879 | ||
|
|
62377ae7ad | ||
|
|
7498e22278 | ||
|
|
af6c9e074e | ||
|
|
71dba654b8 | ||
|
|
ba69fcf824 | ||
|
|
8219ac0168 | ||
|
|
47f66676e4 | ||
|
|
31d9479d17 | ||
|
|
6a8eae7ce4 | ||
|
|
3bddfc21ce | ||
|
|
975a16c74b | ||
|
|
840da0e935 | ||
|
|
0e22f3f8fa | ||
|
|
ff67fb6a4f | ||
|
|
97f37d0def | ||
|
|
37171d174b | ||
|
|
f010c13661 | ||
|
|
84622af5f8 | ||
|
|
024dad6663 | ||
|
|
f1998121aa | ||
|
|
94ca311616 | ||
|
|
44c4bbb9ab | ||
|
|
0c263c98c9 | ||
|
|
c235dc8d4d | ||
|
|
1b7eda0f2c | ||
|
|
f3725b7184 | ||
|
|
00a4b51ec1 | ||
|
|
2cf042fce9 | ||
|
|
55a8fdfee5 | ||
|
|
1ab5323f34 | ||
|
|
fb4ba490af |
2
.github/copilot-instructions.md
vendored
2
.github/copilot-instructions.md
vendored
@@ -63,7 +63,7 @@ task setup # Install all dependencies (Python + Node)
|
||||
task dev:services # Start Postgres & Mailpit containers
|
||||
task py # Start FastAPI backend (port 9000)
|
||||
task ui # Start Nuxt frontend (port 3000)
|
||||
task docs # Start MkDocs documentation server
|
||||
task docs # Start Zensical documentation server
|
||||
```
|
||||
|
||||
**Code generation (REQUIRED after schema changes):**
|
||||
|
||||
2
.github/workflows/docs.yml
vendored
2
.github/workflows/docs.yml
vendored
@@ -30,7 +30,7 @@ jobs:
|
||||
run: uv sync --only-group docs --no-install-project
|
||||
|
||||
- name: Build docs
|
||||
run: uv run --no-project mkdocs build -d site
|
||||
run: uv run --no-project zensical build
|
||||
working-directory: docs
|
||||
|
||||
- name: Upload artifact
|
||||
|
||||
@@ -29,7 +29,7 @@ tasks:
|
||||
desc: runs the documentation server
|
||||
dir: docs
|
||||
cmds:
|
||||
- uv run python -m mkdocs serve
|
||||
- uv run zensical serve
|
||||
|
||||
setup:ui:
|
||||
desc: setup frontend dependencies
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
###############################################
|
||||
# Frontend Build
|
||||
###############################################
|
||||
FROM node:24@sha256:050bf2bbe33c1d6754e060bec89378a79ed831f04a7bb1a53fe45e997df7b3bb \
|
||||
FROM node:24@sha256:8530f76a96d88820d288761f022e318970dda93d01536919fbc16076b7983e63 \
|
||||
AS frontend-builder
|
||||
|
||||
WORKDIR /frontend
|
||||
|
||||
@@ -17,6 +17,31 @@
|
||||
--md-default-accent-bg-color: #1f1e1e;
|
||||
}
|
||||
|
||||
/*
|
||||
* Zensical's "modern" theme ships a flat header that uses the page background
|
||||
* color. Restore the classic Material colored app-bar (and matching nav tabs)
|
||||
* driven by the brand orange, and brand the link color to match.
|
||||
*/
|
||||
.md-header,
|
||||
.md-tabs {
|
||||
background-color: var(--md-primary-fg-color);
|
||||
color: var(--md-primary-bg-color);
|
||||
}
|
||||
|
||||
/*
|
||||
* Brand the accent colors. The modern theme leaves links, the nav active-item
|
||||
* pill, and the announce banner on its default indigo accent (the latter two
|
||||
* via --md-accent-fg-color--transparent), which clashes with the orange. The
|
||||
* [scheme][primary] selector matches the theme's own (0,2,0) accent rules so
|
||||
* the override wins in both light (mealie) and dark (slate) modes.
|
||||
*/
|
||||
[data-md-color-scheme="mealie"][data-md-color-primary="indigo"],
|
||||
[data-md-color-scheme="slate"][data-md-color-primary="indigo"] {
|
||||
--md-typeset-a-color: var(--md-primary-fg-color);
|
||||
--md-accent-fg-color: #e58325;
|
||||
--md-accent-fg-color--transparent: #e583251a;
|
||||
}
|
||||
|
||||
/* frontpage elements */
|
||||
.tx-hero h1 {
|
||||
font-size: 2.41rem !important;
|
||||
@@ -64,7 +89,7 @@ th {
|
||||
}
|
||||
|
||||
.announce-left > a {
|
||||
color: #e0e0e0;
|
||||
color: var(--md-default-fg-color);
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ If you have another provider you'd like to use, such as Azure, you can configure
|
||||
|
||||
Note that some models are capable of handling multiple features (e.g. `gpt-5` can handle both normal chat requests and image recognition requests). You may configure one provider for multiple provider features.
|
||||
|
||||
While Mealie has prompts for each AI task, you can override these with your own prompts if you'd like. For more information, check out the [backend configuration](./installation/ai-providers.md).
|
||||
While Mealie has prompts for each AI task, you can override these with your own prompts if you'd like. For more information, check out the [backend configuration](./backend-config.md).
|
||||
|
||||
## AI Features
|
||||
- The OpenAI Ingredient Parser can be used as an alternative to the NLP and Brute Force parsers. Simply choose the OpenAI parser while parsing ingredients (:octicons-tag-24: v1.7.0)
|
||||
|
||||
@@ -31,7 +31,7 @@ To deploy mealie on your local network, it is highly recommended to use Docker t
|
||||
We've gone through a few versions of Mealie v1 deployment targets. We have settled on a single container deployment, and we've begun publishing the nightly container on github containers. If you're looking to move from the old nightly (split containers _or_ the omni image) to the new nightly, there are a few things you need to do:
|
||||
|
||||
1. Take a backup just in case!
|
||||
2. Replace the image for the API container with `ghcr.io/mealie-recipes/mealie:v3.19.0`
|
||||
2. Replace the image for the API container with `ghcr.io/mealie-recipes/mealie:v3.19.2`
|
||||
3. Take the external port from the frontend container and set that as the port mapped to port `9000` on the new container. The frontend is now served on port 9000 from the new container, so it will need to be mapped for you to have access.
|
||||
4. Restart the container
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ PostgreSQL might be considered if you need to support many concurrent users. In
|
||||
```yaml
|
||||
services:
|
||||
mealie:
|
||||
image: ghcr.io/mealie-recipes/mealie:v3.19.0 # (3)
|
||||
image: ghcr.io/mealie-recipes/mealie:v3.19.2 # (3)
|
||||
container_name: mealie
|
||||
restart: always
|
||||
ports:
|
||||
|
||||
@@ -11,7 +11,7 @@ SQLite is a popular, open source, self-contained, zero-configuration database th
|
||||
```yaml
|
||||
services:
|
||||
mealie:
|
||||
image: ghcr.io/mealie-recipes/mealie:v3.19.0 # (3)
|
||||
image: ghcr.io/mealie-recipes/mealie:v3.19.2 # (3)
|
||||
container_name: mealie
|
||||
restart: always
|
||||
ports:
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
site_name: Mealie
|
||||
demo_url: https://demo.mealie.io
|
||||
site_url: https://docs.mealie.io
|
||||
use_directory_urls: true
|
||||
theme:
|
||||
@@ -16,7 +15,7 @@ theme:
|
||||
toggle:
|
||||
icon: material/weather-sunny
|
||||
name: Switch to light mode
|
||||
custom_dir: docs/overrides
|
||||
custom_dir: overrides
|
||||
features:
|
||||
- content.code.annotate
|
||||
- content.code.copy
|
||||
@@ -28,6 +27,9 @@ theme:
|
||||
- navigation.tabs.sticky
|
||||
favicon: assets/img/favicon.png
|
||||
name: material
|
||||
font:
|
||||
text: Roboto
|
||||
code: Roboto Mono
|
||||
icon:
|
||||
logo: material/silverware-variant
|
||||
|
||||
@@ -50,6 +52,8 @@ markdown_extensions:
|
||||
class: mermaid
|
||||
format: !!python/name:pymdownx.superfences.fence_code_format
|
||||
- pymdownx.details
|
||||
extra:
|
||||
demo_url: https://demo.mealie.io
|
||||
extra_css:
|
||||
- assets/stylesheets/custom.css
|
||||
extra_javascript:
|
||||
|
||||
@@ -228,7 +228,7 @@
|
||||
class="md-button md-button--primary">
|
||||
Get started
|
||||
</a>
|
||||
<a href="{{ config.demo_url }}" title="{{ lang.t('source.link.title') }}" target="_blank" class="md-button">
|
||||
<a href="{{ config.extra.demo_url }}" title="View the Mealie demo" target="_blank" class="md-button">
|
||||
View the Demo
|
||||
</a>
|
||||
</div>
|
||||
@@ -38,7 +38,7 @@ export const LOCALES = [
|
||||
{
|
||||
name: "Svenska (Swedish)",
|
||||
value: "sv-SE",
|
||||
progress: 75,
|
||||
progress: 76,
|
||||
dir: "ltr",
|
||||
pluralFoodHandling: "always",
|
||||
},
|
||||
@@ -52,7 +52,7 @@ export const LOCALES = [
|
||||
{
|
||||
name: "Slovenščina (Slovenian)",
|
||||
value: "sl-SI",
|
||||
progress: 56,
|
||||
progress: 57,
|
||||
dir: "ltr",
|
||||
pluralFoodHandling: "always",
|
||||
},
|
||||
@@ -73,7 +73,7 @@ export const LOCALES = [
|
||||
{
|
||||
name: "Română (Romanian)",
|
||||
value: "ro-RO",
|
||||
progress: 59,
|
||||
progress: 60,
|
||||
dir: "ltr",
|
||||
pluralFoodHandling: "always",
|
||||
},
|
||||
@@ -108,7 +108,7 @@ export const LOCALES = [
|
||||
{
|
||||
name: "Nederlands (Dutch)",
|
||||
value: "nl-NL",
|
||||
progress: 97,
|
||||
progress: 98,
|
||||
dir: "ltr",
|
||||
pluralFoodHandling: "always",
|
||||
},
|
||||
@@ -150,7 +150,7 @@ export const LOCALES = [
|
||||
{
|
||||
name: "Íslenska (Icelandic)",
|
||||
value: "is-IS",
|
||||
progress: 56,
|
||||
progress: 57,
|
||||
dir: "ltr",
|
||||
pluralFoodHandling: "always",
|
||||
},
|
||||
@@ -248,14 +248,14 @@ export const LOCALES = [
|
||||
{
|
||||
name: "Deutsch (German)",
|
||||
value: "de-DE",
|
||||
progress: 98,
|
||||
progress: 99,
|
||||
dir: "ltr",
|
||||
pluralFoodHandling: "always",
|
||||
},
|
||||
{
|
||||
name: "Dansk (Danish)",
|
||||
value: "da-DK",
|
||||
progress: 99,
|
||||
progress: 100,
|
||||
dir: "ltr",
|
||||
pluralFoodHandling: "always",
|
||||
},
|
||||
@@ -276,7 +276,7 @@ export const LOCALES = [
|
||||
{
|
||||
name: "Български (Bulgarian)",
|
||||
value: "bg-BG",
|
||||
progress: 71,
|
||||
progress: 72,
|
||||
dir: "ltr",
|
||||
pluralFoodHandling: "always",
|
||||
},
|
||||
|
||||
@@ -224,8 +224,8 @@
|
||||
"add-field": "Tilføj felt",
|
||||
"date-created": "Oprettet",
|
||||
"date-updated": "Opdateret",
|
||||
"key": "Key",
|
||||
"value": "Value"
|
||||
"key": "Nøgle",
|
||||
"value": "Værdi"
|
||||
},
|
||||
"group": {
|
||||
"are-you-sure-you-want-to-delete-the-group": "Er du sikker på, du vil slette <b>{groupName}<b/>?",
|
||||
@@ -287,37 +287,37 @@
|
||||
"total-households": "Husstande i Alt",
|
||||
"you-must-select-a-group-before-selecting-a-household": "Du skal vælge en gruppe, før du vælger en husstand",
|
||||
"ai-provider-settings": {
|
||||
"ai-provider-settings": "AI Provider Settings",
|
||||
"ai-provider": "AI Provider",
|
||||
"ai-providers": "AI Providers",
|
||||
"ai-provider-settings-description": "Configure AI providers to enable AI-powered features, such as enhanced ingredient parsing, creating recipes from videos, and more!",
|
||||
"providers": "Providers",
|
||||
"create-provider": "Create Provider",
|
||||
"edit-provider": "Edit Provider",
|
||||
"default-provider": "Default Provider",
|
||||
"default-provider-description": "Required to enable AI features",
|
||||
"audio-provider": "Audio Provider",
|
||||
"audio-provider-description": "Enables audio transcription features, such as creating recipes from videos",
|
||||
"image-provider": "Image Provider",
|
||||
"image-provider-description": "Enables image recognition features, such as creating recipes from images",
|
||||
"provider-name": "Provider Name",
|
||||
"api-key": "API Key",
|
||||
"api-key-description-create": "Your provider's API key for authentication. If your service (e.g. Ollama) doesn't use an API key, you still have to put something here.",
|
||||
"api-key-description-edit": "Leave this blank unless you want to change it.",
|
||||
"base-url": "Base URL",
|
||||
"base-url-description": "If you're using OpenAI leave this blank. Must be an OpenAI-compatible endpoint (e.g. \"http://localhost:11434/v1\").",
|
||||
"ai-provider-settings": "AI-udbyderindstillinger",
|
||||
"ai-provider": "AI-udbyder",
|
||||
"ai-providers": "AI-udbydere",
|
||||
"ai-provider-settings-description": "Konfigurér AI-udbydere for at slå AI-funktioner til, såsom forbedret ingredienshåndtering, at oprette opskrifter fra videoer med mere.",
|
||||
"providers": "Udbydere",
|
||||
"create-provider": "Opret udbyder",
|
||||
"edit-provider": "Redigér udbyder",
|
||||
"default-provider": "Standardudbyder",
|
||||
"default-provider-description": "Påkrævet for at slå AI-funktioner til",
|
||||
"audio-provider": "Lydudbyder",
|
||||
"audio-provider-description": "Slå lydtranskriberingsfunktioner til, såsom at oprette opskrifter fra videoer",
|
||||
"image-provider": "Billedudbyder",
|
||||
"image-provider-description": "Slår billedgenkendelsesfunktioner til, såsom at oprette opskrifter fra billeder",
|
||||
"provider-name": "Udbydernavn",
|
||||
"api-key": "API-nøgle",
|
||||
"api-key-description-create": "Din udbyders API-nøgle til godkendelse. Hvis din udbyder ikke benytter en API-nøgle (eks. Ollama), skal du stadig skrive ét eller andet,",
|
||||
"api-key-description-edit": "Undlad at udfylde dette, medmindre du vil ændre det.",
|
||||
"base-url": "Basis-URL",
|
||||
"base-url-description": "Undlad at udfylde, hvis du benytter OpenAI. Skal være et OpenAI-kompatibelt endpoint (eks. \"http://localhost:11434/v1\").",
|
||||
"model": "Model",
|
||||
"model-description": "Which model your AI provider should use (e.g. \"gpt-5\").",
|
||||
"request-timeout-seconds": "Request Timeout (seconds)",
|
||||
"provider-created": "Provider created",
|
||||
"provider-updated": "Provider updated",
|
||||
"provider-deleted": "Provider deleted",
|
||||
"provider-create-failed": "Failed to create provider",
|
||||
"provider-update-failed": "Failed to update provider",
|
||||
"provider-delete-failed": "Failed to delete provider",
|
||||
"request-headers": "Request Headers",
|
||||
"request-params": "Request Parameters",
|
||||
"no-default-provider-warning": "You have not set a default provider, so AI features are disabled"
|
||||
"model-description": "Hvilken model skal din udbyder benytte (eks. \"gpt-5\")?",
|
||||
"request-timeout-seconds": "Forespørgsels-time-out",
|
||||
"provider-created": "Udbyder oprettet",
|
||||
"provider-updated": "Udbyder opdateret",
|
||||
"provider-deleted": "Udbyder slettet",
|
||||
"provider-create-failed": "Kunne ikke oprette udbyder",
|
||||
"provider-update-failed": "Kunne ikke opdatere udbyder",
|
||||
"provider-delete-failed": "Kunne ikke slette udbyder",
|
||||
"request-headers": "Forespørgsels-headers",
|
||||
"request-params": "Forespørgselsparametre",
|
||||
"no-default-provider-warning": "Du har ikke sat en standardudbyder, så AI-funktioner er slået fra"
|
||||
}
|
||||
},
|
||||
"household": {
|
||||
@@ -1397,7 +1397,7 @@
|
||||
"already-set-up-bring-to-homepage": "Jeg er allerede oprettet, bare bringe mig til startsiden",
|
||||
"common-settings-for-new-sites": "Her er nogle almindelige indstillinger for nye sites",
|
||||
"setup-complete": "Opsætning færdig!",
|
||||
"ai-providers-description": "Optionally configure AI providers for your group. AI providers enable features like creating recipes from images, importing recipes from videos, and enhanced ingredient parsing. You can always configure this later from your group settings.",
|
||||
"ai-providers-description": "Konfigurér valgfrit AI-udbydere for din gruppe. AI-udbydere muliggør handlinger, såsom at oprette opskrifter fra billeder, importere opskrifter fra videoer, og forbedret håndtering af ingredienser. Det er altid muligt at konfigurere dette senere under dine gruppeindstillinger.",
|
||||
"here-are-a-few-things-to-help-you-get-started": "Her er et par ting, der kan hjælpe dig i gang med Mealie",
|
||||
"restore-from-v1-backup": "Har du en sikkerhedskopi fra en tidligere udgave af Mealie v1? Du kan gendanne den her.",
|
||||
"manage-profile-or-get-invite-link": "Administrer din egen profil, eller tag et invitationslink til at dele med andre."
|
||||
|
||||
@@ -169,7 +169,7 @@
|
||||
"token": "Token",
|
||||
"tuesday": "Τρίτη",
|
||||
"type": "Τύπος",
|
||||
"undo": "Undo",
|
||||
"undo": "Αναίρεση",
|
||||
"update": "Ενημέρωση",
|
||||
"updated": "Ενημερώθηκε",
|
||||
"upload": "Ανέβασμα",
|
||||
@@ -952,7 +952,7 @@
|
||||
"quantity": "Ποσότητα: {0}",
|
||||
"shopping-list": "Λίστα για ψώνια",
|
||||
"shopping-lists": "Λίστες για ψώνια",
|
||||
"add-item": "Add item",
|
||||
"add-item": "Προσθήκη στοιχείου",
|
||||
"food": "Τρόφιμο",
|
||||
"note": "Σημείωση",
|
||||
"label": "Ετικέτα",
|
||||
|
||||
@@ -224,8 +224,8 @@
|
||||
"add-field": "Veld toevoegen",
|
||||
"date-created": "Datum aangemaakt",
|
||||
"date-updated": "Datum bijgewerkt",
|
||||
"key": "Key",
|
||||
"value": "Value"
|
||||
"key": "Sleutel",
|
||||
"value": "Waarde"
|
||||
},
|
||||
"group": {
|
||||
"are-you-sure-you-want-to-delete-the-group": "Weet je zeker dat je <b>{groupName}<b/> wil verwijderen?",
|
||||
@@ -287,37 +287,37 @@
|
||||
"total-households": "Totaal aantal huishoudens",
|
||||
"you-must-select-a-group-before-selecting-a-household": "Kies een groep voordat je een huishouden kiest",
|
||||
"ai-provider-settings": {
|
||||
"ai-provider-settings": "AI Provider Settings",
|
||||
"ai-provider": "AI Provider",
|
||||
"ai-providers": "AI Providers",
|
||||
"ai-provider-settings-description": "Configure AI providers to enable AI-powered features, such as enhanced ingredient parsing, creating recipes from videos, and more!",
|
||||
"providers": "Providers",
|
||||
"create-provider": "Create Provider",
|
||||
"edit-provider": "Edit Provider",
|
||||
"default-provider": "Default Provider",
|
||||
"default-provider-description": "Required to enable AI features",
|
||||
"audio-provider": "Audio Provider",
|
||||
"audio-provider-description": "Enables audio transcription features, such as creating recipes from videos",
|
||||
"image-provider": "Image Provider",
|
||||
"image-provider-description": "Enables image recognition features, such as creating recipes from images",
|
||||
"provider-name": "Provider Name",
|
||||
"api-key": "API Key",
|
||||
"api-key-description-create": "Your provider's API key for authentication. If your service (e.g. Ollama) doesn't use an API key, you still have to put something here.",
|
||||
"api-key-description-edit": "Leave this blank unless you want to change it.",
|
||||
"base-url": "Base URL",
|
||||
"base-url-description": "If you're using OpenAI leave this blank. Must be an OpenAI-compatible endpoint (e.g. \"http://localhost:11434/v1\").",
|
||||
"ai-provider-settings": "AI-aanbieder instellingen",
|
||||
"ai-provider": "AI-aanbieder",
|
||||
"ai-providers": "AI-aanbieders",
|
||||
"ai-provider-settings-description": "Configureer AI-aanbieders om krachtige AI-aangedreven functies, zoals verbeterde ingrediënt parsing, aanmaken van recepten op basis van video's en nog meer!",
|
||||
"providers": "Aanbieders",
|
||||
"create-provider": "Aanbieder aanmaken",
|
||||
"edit-provider": "Aanbieder bewerken",
|
||||
"default-provider": "Standaard aanbieder",
|
||||
"default-provider-description": "Vereist om AI-functies in te schakelen",
|
||||
"audio-provider": "Audio aanbieder",
|
||||
"audio-provider-description": "Maakt audiotransscriptie functionaliteiten mogelijk, waarmee recepten op basis van video's gemaakt kunnen worden",
|
||||
"image-provider": "Afbeelding aanbieder",
|
||||
"image-provider-description": "Maakt beeldherkenning functionaliteiten mogelijk, waarmee recepten op basis van afbeeldingen gemaakt kunnen worden",
|
||||
"provider-name": "Naam aanbieder",
|
||||
"api-key": "API-sleutel",
|
||||
"api-key-description-create": "Je aanbieder's API-sleutel voor authenticatie. Als je service (bijv. Ollama) geen API-sleutel gebruikt, moet je hier alsnog iets invoeren.",
|
||||
"api-key-description-edit": "Laat dit leeg tenzij je het wilt wijzigen.",
|
||||
"base-url": "Basis URL",
|
||||
"base-url-description": "Als je OpenAI gebruikt laat je dit leeg. Moet een OpenAI-compatibel eindpunt zijn (bijv. \"http://localhost:11434/v1\").",
|
||||
"model": "Model",
|
||||
"model-description": "Which model your AI provider should use (e.g. \"gpt-5\").",
|
||||
"request-timeout-seconds": "Request Timeout (seconds)",
|
||||
"provider-created": "Provider created",
|
||||
"provider-updated": "Provider updated",
|
||||
"provider-deleted": "Provider deleted",
|
||||
"provider-create-failed": "Failed to create provider",
|
||||
"provider-update-failed": "Failed to update provider",
|
||||
"provider-delete-failed": "Failed to delete provider",
|
||||
"request-headers": "Request Headers",
|
||||
"request-params": "Request Parameters",
|
||||
"no-default-provider-warning": "You have not set a default provider, so AI features are disabled"
|
||||
"model-description": "Welk model je AI-aanbieder moet gebruiken (bijv. \"gpt-5\").",
|
||||
"request-timeout-seconds": "Verzoek time-out (seconden)",
|
||||
"provider-created": "Aanbieder aangemaakt",
|
||||
"provider-updated": "Aanbieder bijgewerkt",
|
||||
"provider-deleted": "Aanbieder verwijderd",
|
||||
"provider-create-failed": "Aanmaken van aanbieder mislukt",
|
||||
"provider-update-failed": "Bijwerken van aanbieder mislukt",
|
||||
"provider-delete-failed": "Verwijderen van aanbieder mislukt",
|
||||
"request-headers": "Aanvraagheaders",
|
||||
"request-params": "Aanvraag parameters",
|
||||
"no-default-provider-warning": "Je hebt geen standaard aanbieder ingesteld, AI-functies zijn uitgeschakeld"
|
||||
}
|
||||
},
|
||||
"household": {
|
||||
@@ -663,7 +663,7 @@
|
||||
"create-recipe-description": "Maak een nieuw recept.",
|
||||
"create-recipes": "Recepten aanmaken",
|
||||
"import-with-zip": "Importeer met .zip",
|
||||
"create-recipe-from-images": "Create Recipe from Images",
|
||||
"create-recipe-from-images": "Maak een recept op basis van een afbeelding",
|
||||
"create-recipe-from-an-image-description": "Maak een recept door een afbeelding ervan te uploaden. Mealie probeert de tekst met behulp van AI uit de afbeelding te halen en er een recept uit te maken.",
|
||||
"crop-and-rotate-the-image": "Snijd de afbeelding bij zodat alleen tekst zichtbaar is. En draai t plaatje zodat het leesbaar is.",
|
||||
"create-from-images": "Maak recept van een afbeelding",
|
||||
@@ -1397,7 +1397,7 @@
|
||||
"already-set-up-bring-to-homepage": "Ik ben al ingesteld, breng me naar de startpagina",
|
||||
"common-settings-for-new-sites": "Hier zijn enkele algemene instellingen voor nieuwe sites",
|
||||
"setup-complete": "Installatie voltooid!",
|
||||
"ai-providers-description": "Optionally configure AI providers for your group. AI providers enable features like creating recipes from images, importing recipes from videos, and enhanced ingredient parsing. You can always configure this later from your group settings.",
|
||||
"ai-providers-description": "Optioneel kun je AI-aanbieders instellen voor je groep. AI-aanbieders maken functies, zoals het maken van recepten op basis van afbeeldingen, het malen van recepten op basis van video's, en verbeterde ingrediëntenparsing mogelijk. Je kunt dit later altijd instellen vanuit je groepsinstellingen.",
|
||||
"here-are-a-few-things-to-help-you-get-started": "Hier zijn een aantal dingen om je op weg te helpen met Mealie",
|
||||
"restore-from-v1-backup": "Heb je een back-up van een vorig exemplaar van Mealie v1? Deze kan je hier terugzetten.",
|
||||
"manage-profile-or-get-invite-link": "Beheer je eigen profiel, of gebruik een uitnodigingslink om te delen met anderen."
|
||||
|
||||
@@ -98,7 +98,7 @@
|
||||
"dashboard": "Panou de control",
|
||||
"delete": "Șterge",
|
||||
"disabled": "Inactiv",
|
||||
"done": "Done",
|
||||
"done": "Gata",
|
||||
"download": "Descarcă",
|
||||
"duplicate": "Duplicat",
|
||||
"edit": "Editează",
|
||||
@@ -169,7 +169,7 @@
|
||||
"token": "Token",
|
||||
"tuesday": "Marţi",
|
||||
"type": "Tip",
|
||||
"undo": "Undo",
|
||||
"undo": "Anulează acțiunea",
|
||||
"update": "Actualizează",
|
||||
"updated": "Actualizat",
|
||||
"upload": "Încarcă",
|
||||
@@ -368,8 +368,8 @@
|
||||
"any-household": "Orice locuință",
|
||||
"no-meal-plan-defined-yet": "Nici un plan de mese definit încă",
|
||||
"no-meal-planned-for-today": "Nicio masă planificată pentru astăzi",
|
||||
"numberOfDaysPast-hint": "Number of days in the past on page load",
|
||||
"numberOfDaysPast-label": "Default Days in the Past",
|
||||
"numberOfDaysPast-hint": "Numărul de zile din trecut la încărcarea paginii",
|
||||
"numberOfDaysPast-label": "Număr implicit de zile din trecut",
|
||||
"numberOfDays-hint": "Număr de zile pe pagină încărcată",
|
||||
"numberOfDays-label": "Zile implicite",
|
||||
"only-recipes-with-these-categories-will-be-used-in-meal-plans": "Numai rețetele cu aceste categorii vor fi utilizate în Planurile de mese",
|
||||
@@ -675,8 +675,8 @@
|
||||
"create-a-recipe-by-providing-the-name-all-recipes-must-have-unique-names": "Creează o rețetă furnizând numele. Toate rețetele trebuie să aibă nume unice.",
|
||||
"new-recipe-names-must-be-unique": "Numele rețetei trebuie să fie unic",
|
||||
"scrape-recipe": "Importare rețetă",
|
||||
"scrape-recipe-description": "Scrape a recipe by url. Provide the url for the site you want to scrape, and Mealie will attempt to scrape the recipe from that site and add it to your collection.",
|
||||
"scrape-recipe-description-transcription": "You can also provide the url to a video and Mealie will attempt to transcribe it into a recipe.",
|
||||
"scrape-recipe-description": "Extrage o rețetă după url. Introdu url-ul site-ului din care vrei să extragi rețeta, iar Mealie va încerca să o importe și să o adauge în colecția ta.",
|
||||
"scrape-recipe-description-transcription": "Poți introduce și URL-ul unui videoclip, iar Mealie va încerca să îl transcrie într-o rețetă.",
|
||||
"scrape-recipe-have-a-lot-of-recipes": "Ai mai multe rețete pe care vrei să le imporți simultan?",
|
||||
"scrape-recipe-suggest-bulk-importer": "Încearcă importatorul în bulk",
|
||||
"scrape-recipe-have-raw-html-or-json-data": "Ai date de tip HTML sau JSON?",
|
||||
@@ -815,7 +815,7 @@
|
||||
"irreversible-acknowledgment": "Înțeleg că această acțiune este ireversibilă, distructivă și poate provoca pierderea datelor",
|
||||
"restore-backup": "Restaurează backup"
|
||||
},
|
||||
"backup-and-exports": "Backups",
|
||||
"backup-and-exports": "Copii de rezervă",
|
||||
"change-password": "Schimbă parola",
|
||||
"current": "Versiune:",
|
||||
"custom-pages": "Pagini personalizate",
|
||||
@@ -928,17 +928,17 @@
|
||||
"server-side-base-url-error-text": "`BASE_URL` încă este setat la valoarea implicită pe serverul API. Acest lucru va cauza probleme cu link-urile de notificări generate pe server pentru e-mailuri, etc.",
|
||||
"server-side-base-url-success-text": "Adresa URL a serverului nu se potrivește cu cea implicită",
|
||||
"ldap-ready": "LDAP pregătit",
|
||||
"ldap-not-ready": "LDAP Not Ready",
|
||||
"ldap-not-ready": "LDAP nu este pregătit\"",
|
||||
"ldap-ready-error-text": "Nu toate valorile LDAP sunt configurate. Acest lucru poate fi ignorat dacă nu utilizați autentificarea cu LDAP.",
|
||||
"ldap-ready-success-text": "Variabilele LDAP necesare sunt setate.",
|
||||
"build": "Compilare",
|
||||
"recipe-scraper-version": "Versiune \"scraper\" de rețete",
|
||||
"oidc-ready": "OIDC pregătit",
|
||||
"oidc-not-ready": "OIDC Not Ready",
|
||||
"oidc-not-ready": "OIDC nu este pregătit",
|
||||
"oidc-ready-error-text": "Nu toate valorile OIDC sunt configurate. Acest lucru poate fi ignorat dacă nu folosiți autentificarea OIDC.",
|
||||
"oidc-ready-success-text": "Variabilele OIDC necesare sunt setate.",
|
||||
"openai-ready": "OpenAI pregătit",
|
||||
"openai-not-ready": "OpenAI Not Ready",
|
||||
"openai-not-ready": "OpenAI nu este pregătit",
|
||||
"openai-ready-error-text": "Nu toate valorile OpenAI sunt configurate. Acest lucru poate fi ignorat dacă nu utilizaţi caracteristicile OpenAI.",
|
||||
"openai-ready-success-text": "Variabilele necesare OpenAI sunt setate."
|
||||
},
|
||||
@@ -946,15 +946,15 @@
|
||||
"all-lists": "Toate listele",
|
||||
"create-shopping-list": "Creează listă de cumpărături",
|
||||
"from-recipe": "Dintr-o rețetă",
|
||||
"ingredient-of-recipe": "Ingredient of {recipe}",
|
||||
"ingredient-of-recipe": "Ingredient din {recipe}",
|
||||
"list-name": "Nume listă",
|
||||
"new-list": "Listă nouă",
|
||||
"quantity": "Cantitate: {0}",
|
||||
"shopping-list": "Listă de cumpărături",
|
||||
"shopping-lists": "Liste de cumpărături",
|
||||
"add-item": "Add item",
|
||||
"add-item": "Adaugă articol",
|
||||
"food": "Aliment",
|
||||
"note": "Note",
|
||||
"note": "Notă",
|
||||
"label": "Etichetă",
|
||||
"save-label": "Salvează etichetă",
|
||||
"linked-item-warning": "Acest element este legat de una sau mai multe rețete. Ajustarea unităților sau a alimentelor va produce rezultate neașteptate la adăugarea sau scoaterea rețetei din listă.",
|
||||
@@ -978,7 +978,7 @@
|
||||
"are-you-sure-you-want-to-uncheck-all-items": "Sunteți sigur că doriți să debifați toate elementele?",
|
||||
"are-you-sure-you-want-to-delete-checked-items": "Sunteți sigur că doriți să ștergeți toate elementele selectate?",
|
||||
"no-shopping-lists-found": "Nu s-au găsit liste de cumpărături",
|
||||
"item-checked-off": "Checked off {item}"
|
||||
"item-checked-off": "{item} a fost bifat"
|
||||
},
|
||||
"sidebar": {
|
||||
"all-recipes": "Toate reţetele",
|
||||
@@ -1181,18 +1181,18 @@
|
||||
"example-unit-plural": "ex: Linguri",
|
||||
"example-unit-abbreviation-singular": "ex: Lg",
|
||||
"example-unit-abbreviation-plural": "ex: Lg",
|
||||
"standardization": "Standardization",
|
||||
"standardization-description": "How this unit can be represented as a standard unit. This enables unit conversion features such as merging compatible units in shopping lists.",
|
||||
"standard-unit": "Standard Unit",
|
||||
"standard-quantity": "Standard Quantity",
|
||||
"unit-conversion": "Unit Conversion",
|
||||
"standardization": "Standardizare",
|
||||
"standardization-description": "Modul în care această unitate poate fi reprezentată ca unitate standard. Activează funcții de conversie a unităților, cum ar fi combinarea unităților compatibile în listele de cumpărături.",
|
||||
"standard-unit": "Unitate standard",
|
||||
"standard-quantity": "Cantitate standard",
|
||||
"unit-conversion": "Conversie unități",
|
||||
"standard-unit-labels": {
|
||||
"fluid-ounce": "fluid ounce",
|
||||
"cup": "cup",
|
||||
"ounce": "ounce",
|
||||
"pound": "pound",
|
||||
"milliliter": "milliliter",
|
||||
"liter": "liter",
|
||||
"fluid-ounce": "uncie fluidă",
|
||||
"cup": "cană",
|
||||
"ounce": "uncie",
|
||||
"pound": "livră",
|
||||
"milliliter": "mililitru",
|
||||
"liter": "litru",
|
||||
"gram": "gram",
|
||||
"kilogram": "kilogram"
|
||||
}
|
||||
@@ -1514,10 +1514,10 @@
|
||||
"max-length": "Trebuie să aibă cel mult {max} caracter | Trebuie să aibă cel mult {max} caractere"
|
||||
},
|
||||
"announcements": {
|
||||
"announcements": "Announcements",
|
||||
"all-announcements": "All announcements",
|
||||
"mark-all-as-read": "Mark All as Read",
|
||||
"show-announcements-from-mealie": "Show announcements from Mealie",
|
||||
"show-announcements-setting-description": "Whether or not you want to allow users to see announcements from Mealie. When enabled users can still opt-out from seeing them in their user settings"
|
||||
"announcements": "Anunțuri",
|
||||
"all-announcements": "Toate anunțurile",
|
||||
"mark-all-as-read": "Marchează toate ca citite",
|
||||
"show-announcements-from-mealie": "Afișează anunțurile de la Mealie",
|
||||
"show-announcements-setting-description": "Stabilește dacă utilizatorii pot vedea anunțuri de la Mealie. Când opțiunea este activată, utilizatorii pot alege în continuare să nu le vadă în setările personale"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ export default withNuxt({
|
||||
"@stylistic/no-tabs": ["error"],
|
||||
"@stylistic/no-mixed-spaces-and-tabs": ["error", "smart-tabs"],
|
||||
"@typescript-eslint/no-explicit-any": "off",
|
||||
"import/no-extraneous-dependencies": ["error"],
|
||||
"vue/first-attribute-linebreak": "error",
|
||||
"vue/html-closing-bracket-newline": "error",
|
||||
"vue/max-attributes-per-line": [
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "mealie",
|
||||
"version": "3.19.0",
|
||||
"version": "3.19.2",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "nuxt dev",
|
||||
@@ -21,18 +21,24 @@
|
||||
"@mdi/js": "^7.4.47",
|
||||
"@nuxt/fonts": "^0.11.4",
|
||||
"@nuxtjs/i18n": "^9.2.1",
|
||||
"@sphinxxxx/color-conversion": "^2.2.2",
|
||||
"@vite-pwa/nuxt": "^0.10.6",
|
||||
"@vueuse/core": "^12.7.0",
|
||||
"@vueuse/shared": "^14.3.0",
|
||||
"axios": "^1.8.1",
|
||||
"date-fns": "^4.1.0",
|
||||
"dompurify": "^3.4.7",
|
||||
"fuse.js": "^7.1.0",
|
||||
"isomorphic-dompurify": "^3.4.0",
|
||||
"json-editor-vue": "^0.18.1",
|
||||
"marked": "^15.0.12",
|
||||
"nuxt": "^4.4.2",
|
||||
"sse.js": "^2.8.0",
|
||||
"ufo": "^1.6.4",
|
||||
"vue": "^3.5.35",
|
||||
"vue-advanced-cropper": "^2.8.9",
|
||||
"vue-draggable-plus": "^0.6.0",
|
||||
"vue-i18n": "^11.4.4",
|
||||
"vuetify": "^4.0.5",
|
||||
"vuetify-nuxt-module": "^0.19.5"
|
||||
},
|
||||
@@ -41,6 +47,7 @@
|
||||
"@stylistic/eslint-plugin": "^5.4.0",
|
||||
"@types/node": "^25.5.2",
|
||||
"@types/sortablejs": "^1.15.8",
|
||||
"@vitejs/plugin-vue": "^6.0.7",
|
||||
"eslint": "^9.22.0",
|
||||
"eslint-config-prettier": "^10.0.2",
|
||||
"eslint-plugin-format": "^1.0.1",
|
||||
|
||||
5007
frontend/yarn.lock
5007
frontend/yarn.lock
File diff suppressed because it is too large
Load Diff
@@ -50,13 +50,19 @@ def determine_secrets(data_dir: Path, secret: str, production: bool) -> str:
|
||||
secrets_file = data_dir.joinpath(secret)
|
||||
if secrets_file.is_file():
|
||||
with open(secrets_file) as f:
|
||||
return f.read()
|
||||
else:
|
||||
data_dir.mkdir(parents=True, exist_ok=True)
|
||||
with open(secrets_file, "w") as f:
|
||||
new_secret = secrets.token_hex(32)
|
||||
f.write(new_secret)
|
||||
return new_secret
|
||||
existing_secret = f.read().strip()
|
||||
if existing_secret:
|
||||
return existing_secret
|
||||
|
||||
data_dir.mkdir(parents=True, exist_ok=True)
|
||||
new_secret = secrets.token_hex(32)
|
||||
tmp_file = secrets_file.with_suffix(".tmp")
|
||||
with open(tmp_file, "w") as f:
|
||||
f.write(new_secret)
|
||||
f.flush()
|
||||
os.fsync(f.fileno())
|
||||
tmp_file.replace(secrets_file)
|
||||
return new_secret
|
||||
|
||||
|
||||
def get_secrets_dir() -> str | None:
|
||||
|
||||
@@ -3,7 +3,7 @@ from typing import TYPE_CHECKING
|
||||
from sqlalchemy import ForeignKey, String
|
||||
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
||||
|
||||
from .._model_base import BaseMixins, SqlAlchemyBase
|
||||
from .._model_base import BaseMixins, FilterableColumn, SqlAlchemyBase
|
||||
from .._model_utils.auto_init import auto_init
|
||||
from .._model_utils.guid import GUID
|
||||
|
||||
@@ -14,14 +14,14 @@ if TYPE_CHECKING:
|
||||
|
||||
class GroupRecipeAction(SqlAlchemyBase, BaseMixins):
|
||||
__tablename__ = "recipe_actions"
|
||||
id: Mapped[GUID] = mapped_column(GUID, primary_key=True, default=GUID.generate)
|
||||
group_id: Mapped[GUID] = mapped_column(GUID, ForeignKey("groups.id"), index=True)
|
||||
id: FilterableColumn[GUID] = mapped_column(GUID, primary_key=True, default=GUID.generate)
|
||||
group_id: FilterableColumn[GUID] = mapped_column(GUID, ForeignKey("groups.id"), index=True)
|
||||
group: Mapped["Group"] = relationship("Group", back_populates="recipe_actions", single_parent=True)
|
||||
household_id: Mapped[GUID | None] = mapped_column(GUID, ForeignKey("households.id"), index=True)
|
||||
household_id: FilterableColumn[GUID | None] = mapped_column(GUID, ForeignKey("households.id"), index=True)
|
||||
household: Mapped["Household"] = relationship("Household", back_populates="recipe_actions")
|
||||
|
||||
action_type: Mapped[str] = mapped_column(String, index=True)
|
||||
title: Mapped[str] = mapped_column(String, index=True)
|
||||
action_type: FilterableColumn[str] = mapped_column(String, index=True)
|
||||
title: FilterableColumn[str] = mapped_column(String, index=True)
|
||||
url: Mapped[str] = mapped_column(String)
|
||||
|
||||
@auto_init()
|
||||
|
||||
@@ -18,17 +18,17 @@
|
||||
"yield": "Recoltă",
|
||||
"yields": "Producţii"
|
||||
},
|
||||
"and-amount": "and {amount}",
|
||||
"or-ingredient": "or {ingredient}",
|
||||
"and-amount": "și {amount}",
|
||||
"or-ingredient": "sau {ingredient}",
|
||||
"create-progress": {
|
||||
"creating-recipe-with-ai": "Creating recipe with AI...",
|
||||
"creating-recipe-from-transcript-with-ai": "Creating recipe from transcript with AI...",
|
||||
"creating-recipe-from-webpage-data": "Creating recipe from webpage data...",
|
||||
"downloading-image": "Downloading image...",
|
||||
"downloading-video": "Downloading video...",
|
||||
"extracting-recipe-data": "Extracting recipe data...",
|
||||
"fetching-webpage": "Fetching webpage...",
|
||||
"transcribing-audio-with-ai": "Transcribing audio with AI..."
|
||||
"creating-recipe-with-ai": "Se creează rețeta cu AI...",
|
||||
"creating-recipe-from-transcript-with-ai": "Se creează rețeta din transcriere cu AI...",
|
||||
"creating-recipe-from-webpage-data": "Se creează rețeta din datele paginii web...",
|
||||
"downloading-image": "Se descarcă imaginea...",
|
||||
"downloading-video": "Se descarcă videoclipul...",
|
||||
"extracting-recipe-data": "Se extrag datele rețetei...",
|
||||
"fetching-webpage": "Se preia pagina web...",
|
||||
"transcribing-audio-with-ai": "Se transcrie sunetul cu AI..."
|
||||
}
|
||||
},
|
||||
"mealplan": {
|
||||
|
||||
@@ -6427,8 +6427,8 @@
|
||||
"sugar": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "sugar",
|
||||
"plural_name": "sugar"
|
||||
"name": "ζάχαρη",
|
||||
"plural_name": "ζάχαρη"
|
||||
},
|
||||
"brown sugar": {
|
||||
"aliases": [
|
||||
@@ -6542,8 +6542,8 @@
|
||||
"raw sugar": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "raw sugar",
|
||||
"plural_name": "raw sugar"
|
||||
"name": "ακατέργαστη ζάχαρη",
|
||||
"plural_name": "ακατέργαστη ζάχαρη"
|
||||
},
|
||||
"golden syrup": {
|
||||
"aliases": [],
|
||||
@@ -6560,8 +6560,8 @@
|
||||
"liquid stevia": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "liquid stevia",
|
||||
"plural_name": "liquid stevia"
|
||||
"name": "υγρή στέβια",
|
||||
"plural_name": "υγρή στέβια"
|
||||
},
|
||||
"grenadine": {
|
||||
"aliases": [],
|
||||
@@ -16087,8 +16087,8 @@
|
||||
"fish oil": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "fish oil",
|
||||
"plural_name": "fish oil"
|
||||
"name": "ιχθυέλαιο",
|
||||
"plural_name": "ιχθυέλαιο"
|
||||
},
|
||||
"lime essential oil": {
|
||||
"aliases": [],
|
||||
@@ -16099,8 +16099,8 @@
|
||||
"probiotic": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "probiotic",
|
||||
"plural_name": "probiotics"
|
||||
"name": "προβιοτικό",
|
||||
"plural_name": "προβιοτικά"
|
||||
},
|
||||
"activated charcoal": {
|
||||
"aliases": [],
|
||||
@@ -16111,8 +16111,8 @@
|
||||
"egg powder": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "egg powder",
|
||||
"plural_name": "egg powder"
|
||||
"name": "σκόνη αυγών",
|
||||
"plural_name": "σκόνη αυγών"
|
||||
},
|
||||
"reishi mushroom": {
|
||||
"aliases": [],
|
||||
@@ -16267,8 +16267,8 @@
|
||||
"banana powder": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "banana powder",
|
||||
"plural_name": "banana powder"
|
||||
"name": "σκόνη μπανάνας",
|
||||
"plural_name": "σκόνη μπανάνας"
|
||||
},
|
||||
"chaga mushroom powder": {
|
||||
"aliases": [],
|
||||
|
||||
@@ -3930,7 +3930,7 @@
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "andouille",
|
||||
"plural_name": "andouilles"
|
||||
"plural_name": "andouillette"
|
||||
},
|
||||
"boneless lamb": {
|
||||
"aliases": [],
|
||||
|
||||
@@ -1856,7 +1856,7 @@
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "onion seed",
|
||||
"plural_name": "onion seeds"
|
||||
"plural_name": "Semințe de ceapă"
|
||||
},
|
||||
"watermelon seed": {
|
||||
"aliases": [],
|
||||
@@ -1873,8 +1873,8 @@
|
||||
"melon seed": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "melon seed",
|
||||
"plural_name": "melon seeds"
|
||||
"name": "Sămânță de pepene",
|
||||
"plural_name": "Semințe de pepene"
|
||||
},
|
||||
"lotus seed": {
|
||||
"aliases": [],
|
||||
@@ -2038,19 +2038,19 @@
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "brânză mozzarella",
|
||||
"plural_name": "mozzarella cheese"
|
||||
"plural_name": "brânză mozzarella"
|
||||
},
|
||||
"feta cheese": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "feta cheese",
|
||||
"plural_name": "feta cheese"
|
||||
"name": "brânză feta",
|
||||
"plural_name": "brânză feta"
|
||||
},
|
||||
"ricotta cheese": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "ricotta cheese",
|
||||
"plural_name": "ricotta cheese"
|
||||
"name": "brânză ricotta",
|
||||
"plural_name": "brânză ricotta"
|
||||
},
|
||||
"cheddar-jack cheese": {
|
||||
"aliases": [],
|
||||
@@ -2067,32 +2067,32 @@
|
||||
"blue cheese": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "blue cheese",
|
||||
"plural_name": "blue cheese"
|
||||
"name": "brânză cu mucegai albastru",
|
||||
"plural_name": "brânzeturi cu mucegai albastru"
|
||||
},
|
||||
"goat cheese": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "goat cheese",
|
||||
"plural_name": "goat cheese"
|
||||
"name": "brânză de capră",
|
||||
"plural_name": "brânzeturi de capră"
|
||||
},
|
||||
"fresh mozzarella cheese": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "fresh mozzarella cheese",
|
||||
"plural_name": "fresh mozzarella cheese"
|
||||
"name": "mozzarella proaspătă",
|
||||
"plural_name": "mozzarella proaspătă"
|
||||
},
|
||||
"swis cheese": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "swis cheese",
|
||||
"plural_name": "swis cheese"
|
||||
"name": "brânză elvețiană",
|
||||
"plural_name": "brânzeturi elvețiene"
|
||||
},
|
||||
"pecorino cheese": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "pecorino cheese",
|
||||
"plural_name": "pecorino cheese"
|
||||
"name": "brânză pecorino",
|
||||
"plural_name": "brânză pecorino"
|
||||
},
|
||||
"gruyere cheese": {
|
||||
"aliases": [],
|
||||
@@ -2109,8 +2109,8 @@
|
||||
"cottage cheese": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "cottage cheese",
|
||||
"plural_name": "cottage cheese"
|
||||
"name": "brânză de vaci",
|
||||
"plural_name": "brânză de vaci"
|
||||
},
|
||||
"american cheese": {
|
||||
"aliases": [],
|
||||
@@ -2121,8 +2121,8 @@
|
||||
"provolone cheese": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "provolone cheese",
|
||||
"plural_name": "provolone cheese"
|
||||
"name": "brânză provolone",
|
||||
"plural_name": "brânză provolone"
|
||||
},
|
||||
"mexican cheese blend": {
|
||||
"aliases": [],
|
||||
@@ -2169,7 +2169,7 @@
|
||||
"gouda cheese": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "gouda cheese",
|
||||
"name": "brânză gouda",
|
||||
"plural_name": "gouda cheese"
|
||||
},
|
||||
"cotija cheese": {
|
||||
@@ -2187,8 +2187,8 @@
|
||||
"smoked cheese": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "smoked cheese",
|
||||
"plural_name": "smoked cheese"
|
||||
"name": "brânză afumată",
|
||||
"plural_name": "brânză afumată"
|
||||
},
|
||||
"halloumi cheese": {
|
||||
"aliases": [],
|
||||
@@ -2229,7 +2229,7 @@
|
||||
"burrata cheese": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "burrata cheese",
|
||||
"name": "brânză burrata",
|
||||
"plural_name": "burrata cheese"
|
||||
},
|
||||
"havarti cheese": {
|
||||
@@ -2283,8 +2283,8 @@
|
||||
"raclette cheese": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "raclette cheese",
|
||||
"plural_name": "raclette cheese"
|
||||
"name": "brânză raclette",
|
||||
"plural_name": "brânză raclette"
|
||||
},
|
||||
"colby-jack cheese": {
|
||||
"aliases": [],
|
||||
@@ -2457,8 +2457,8 @@
|
||||
"hard goat cheese": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "hard goat cheese",
|
||||
"plural_name": "hard goat cheese"
|
||||
"name": "brânză tare de capră",
|
||||
"plural_name": "brânză tare de capră"
|
||||
},
|
||||
"kashkaval cheese": {
|
||||
"aliases": [],
|
||||
@@ -2469,8 +2469,8 @@
|
||||
"sheep cheese": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "sheep cheese",
|
||||
"plural_name": "sheep cheese"
|
||||
"name": "brânză de oaie",
|
||||
"plural_name": "brânză de oaie"
|
||||
},
|
||||
"amul cheese": {
|
||||
"aliases": [],
|
||||
@@ -2630,49 +2630,49 @@
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "lapte",
|
||||
"plural_name": "milk"
|
||||
"plural_name": "lapte"
|
||||
},
|
||||
"heavy cream": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "smântână pentru frișcă",
|
||||
"plural_name": "heavy cream"
|
||||
"plural_name": "smântână pentru frișcă"
|
||||
},
|
||||
"sour cream": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "smântână",
|
||||
"plural_name": "sour cream"
|
||||
"plural_name": "smântână"
|
||||
},
|
||||
"buttermilk": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "buttermilk",
|
||||
"plural_name": "buttermilk"
|
||||
"name": "lapte bătut",
|
||||
"plural_name": "lapte bătut"
|
||||
},
|
||||
"yogurt": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "iaurt",
|
||||
"plural_name": "yogurts"
|
||||
"plural_name": "iaurt"
|
||||
},
|
||||
"greek yogurt": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "greek yogurt",
|
||||
"plural_name": "greek yogurts"
|
||||
"name": "iaurt grecesc",
|
||||
"plural_name": "iaurturi grecești"
|
||||
},
|
||||
"cream": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "cream",
|
||||
"plural_name": "cream"
|
||||
"name": "smântână",
|
||||
"plural_name": "smântână"
|
||||
},
|
||||
"whipped cream": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "whipped cream",
|
||||
"plural_name": "whipped cream"
|
||||
"name": "frișcă",
|
||||
"plural_name": "frișcă"
|
||||
},
|
||||
"ghee": {
|
||||
"aliases": [
|
||||
@@ -2692,7 +2692,7 @@
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "lapte condensat",
|
||||
"plural_name": "condensed milk"
|
||||
"plural_name": "lapte condensat"
|
||||
},
|
||||
"half and half": {
|
||||
"aliases": [],
|
||||
@@ -2710,7 +2710,7 @@
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "înghețată",
|
||||
"plural_name": "ice cream"
|
||||
"plural_name": "înghețată"
|
||||
},
|
||||
"margarine": {
|
||||
"aliases": [],
|
||||
@@ -2734,7 +2734,7 @@
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "lapte praf",
|
||||
"plural_name": "milk powder"
|
||||
"plural_name": "lapte praf"
|
||||
},
|
||||
"curd": {
|
||||
"aliases": [],
|
||||
@@ -2788,7 +2788,7 @@
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "lapte cu ciocolată",
|
||||
"plural_name": "chocolate milk"
|
||||
"plural_name": "lapte cu ciocolată"
|
||||
},
|
||||
"liquid egg substitute": {
|
||||
"aliases": [],
|
||||
@@ -2872,7 +2872,7 @@
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "ganache",
|
||||
"plural_name": "ganaches"
|
||||
"plural_name": "ganache"
|
||||
},
|
||||
"cajeta": {
|
||||
"aliases": [],
|
||||
@@ -2883,8 +2883,8 @@
|
||||
"duck egg": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "duck egg",
|
||||
"plural_name": "duck eggs"
|
||||
"name": "ou de rață",
|
||||
"plural_name": "ouă de rață"
|
||||
},
|
||||
"salted egg": {
|
||||
"aliases": [],
|
||||
@@ -2908,7 +2908,7 @@
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "lapte crud",
|
||||
"plural_name": "raw milk"
|
||||
"plural_name": "lapte crud"
|
||||
},
|
||||
"lime curd": {
|
||||
"aliases": [],
|
||||
@@ -3027,7 +3027,7 @@
|
||||
"chocolate milk powder": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "chocolate milk powder",
|
||||
"name": "lapte praf de ciocolată",
|
||||
"plural_name": "chocolate milk powder"
|
||||
},
|
||||
"liquid rennet": {
|
||||
@@ -3337,7 +3337,7 @@
|
||||
"smoked tofu": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "smoked tofu",
|
||||
"name": "tofu afumat",
|
||||
"plural_name": "smoked tofus"
|
||||
},
|
||||
"coconut powder": {
|
||||
|
||||
@@ -9,13 +9,13 @@
|
||||
"name": "lingură",
|
||||
"plural_name": "linguri",
|
||||
"description": "",
|
||||
"abbreviation": "tbsp"
|
||||
"abbreviation": "lg"
|
||||
},
|
||||
"cup": {
|
||||
"name": "cană",
|
||||
"plural_name": "căni",
|
||||
"description": "",
|
||||
"abbreviation": "c"
|
||||
"abbreviation": "cană"
|
||||
},
|
||||
"fluid-ounce": {
|
||||
"name": "uncie fluidă",
|
||||
@@ -30,7 +30,7 @@
|
||||
"abbreviation": "pt"
|
||||
},
|
||||
"quart": {
|
||||
"name": "quart",
|
||||
"name": "sfert de galon",
|
||||
"plural_name": "sferturi de galon",
|
||||
"description": "",
|
||||
"abbreviation": "qt"
|
||||
@@ -139,8 +139,8 @@
|
||||
"abbreviation": ""
|
||||
},
|
||||
"sprig": {
|
||||
"name": "sprig",
|
||||
"plural_name": "sprigs",
|
||||
"name": "crenguță",
|
||||
"plural_name": "crenguțe",
|
||||
"description": "",
|
||||
"abbreviation": ""
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
[build]
|
||||
publish = "docs/site/"
|
||||
command = """
|
||||
pip3 install mkdocs-material &&
|
||||
pip3 install zensical &&
|
||||
cd docs &&
|
||||
mkdocs build
|
||||
zensical build
|
||||
"""
|
||||
|
||||
[[headers]]
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[project]
|
||||
name = "mealie"
|
||||
version = "3.19.0"
|
||||
version = "3.19.2"
|
||||
description = "A Recipe Manager"
|
||||
authors = [{ name = "Hayden", email = "hay-kot@pm.me" }]
|
||||
license = "AGPL-3.0-only"
|
||||
@@ -9,7 +9,7 @@ dependencies = [
|
||||
"Jinja2==3.1.6",
|
||||
"Pillow==12.2.0",
|
||||
"PyYAML==6.0.3",
|
||||
"SQLAlchemy==2.0.49",
|
||||
"SQLAlchemy==2.0.50",
|
||||
"aiofiles==25.1.0",
|
||||
"alembic==1.18.4",
|
||||
"aniso8601==10.0.1",
|
||||
@@ -17,21 +17,21 @@ dependencies = [
|
||||
"apprise==1.10.0",
|
||||
"bcrypt==5.0.0",
|
||||
"extruct==0.18.0",
|
||||
"fastapi==0.136.1",
|
||||
"fastapi==0.136.3",
|
||||
"httpx==0.28.1",
|
||||
"lxml==6.1.0",
|
||||
"orjson==3.11.8",
|
||||
"pydantic==2.13.3",
|
||||
"lxml==6.1.1",
|
||||
"orjson==3.11.9",
|
||||
"pydantic==2.13.4",
|
||||
"pyhumps==3.8.0",
|
||||
"python-dateutil==2.9.0.post0",
|
||||
"python-dotenv==1.2.2",
|
||||
"python-ldap==3.4.5",
|
||||
"python-multipart==0.0.27",
|
||||
"python-ldap==3.4.7",
|
||||
"python-multipart==0.0.29",
|
||||
"python-slugify==8.0.4",
|
||||
"recipe-scrapers==15.11.0",
|
||||
"requests==2.33.1",
|
||||
"requests==2.34.2",
|
||||
"tzdata==2026.2",
|
||||
"uvicorn[standard]==0.46.0",
|
||||
"uvicorn[standard]==0.48.0",
|
||||
"beautifulsoup4==4.14.3",
|
||||
"isodate==0.7.2",
|
||||
"text-unidecode==1.3",
|
||||
@@ -39,14 +39,14 @@ dependencies = [
|
||||
"authlib==1.7.2",
|
||||
"html2text==2025.4.15",
|
||||
"paho-mqtt==1.6.1",
|
||||
"pydantic-settings==2.14.0",
|
||||
"pydantic-settings==2.14.1",
|
||||
"pillow-heif==1.3.0",
|
||||
"pyjwt==2.12.1",
|
||||
"openai==2.34.0",
|
||||
"pyjwt==2.13.0",
|
||||
"openai==2.38.0",
|
||||
"typing-extensions==4.15.0",
|
||||
"itsdangerous==2.2.0",
|
||||
"yt-dlp==2026.3.17",
|
||||
"ingredient-parser-nlp==2.6.0",
|
||||
"ingredient-parser-nlp==2.7.0",
|
||||
"pint==0.25.3",
|
||||
"httpx-curl-cffi==0.1.5",
|
||||
]
|
||||
@@ -61,23 +61,23 @@ pgsql = [
|
||||
|
||||
[dependency-groups]
|
||||
docs = [
|
||||
"mkdocs-material==9.7.6",
|
||||
"zensical==0.0.42",
|
||||
]
|
||||
dev = [
|
||||
"coverage==7.13.5",
|
||||
"coverage==7.14.1",
|
||||
"coveragepy-lcov==0.1.2",
|
||||
"mkdocs-material==9.7.6",
|
||||
"mypy==2.0.0",
|
||||
"zensical==0.0.42",
|
||||
"mypy==2.1.0",
|
||||
"pre-commit==4.6.0",
|
||||
"pylint==4.0.5",
|
||||
"pytest==9.0.3",
|
||||
"pytest-asyncio==1.3.0",
|
||||
"rich==15.0.0",
|
||||
"ruff==0.15.12",
|
||||
"types-PyYAML==6.0.12.20260408",
|
||||
"types-python-dateutil==2.9.0.20260408",
|
||||
"ruff==0.15.14",
|
||||
"types-PyYAML==6.0.12.20260518",
|
||||
"types-python-dateutil==2.9.0.20260518",
|
||||
"types-python-slugify==8.0.2.20240310",
|
||||
"types-requests==2.33.0.20260503",
|
||||
"types-requests==2.33.0.20260518",
|
||||
"types-urllib3==1.26.25.14",
|
||||
"pydantic-to-typescript2==1.0.6",
|
||||
"freezegun==1.5.5",
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
{
|
||||
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
|
||||
"prCreation": "immediate",
|
||||
"lockFileMaintenance": {
|
||||
"enabled": true
|
||||
},
|
||||
@@ -24,6 +25,13 @@
|
||||
],
|
||||
"dependencyDashboardApproval": true
|
||||
},
|
||||
{
|
||||
"description": "Always create lockfile maintenance PRs without dashboard approval",
|
||||
"matchUpdateTypes": [
|
||||
"lockFileMaintenance"
|
||||
],
|
||||
"dependencyDashboardApproval": false
|
||||
},
|
||||
{
|
||||
"matchManagers": [
|
||||
"pep621"
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
import json
|
||||
import re
|
||||
from dataclasses import dataclass
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
|
||||
import pytest
|
||||
|
||||
from mealie.core.config import get_app_settings
|
||||
from mealie.core.settings.settings import AppSettings
|
||||
from mealie.core.settings.settings import AppSettings, determine_secrets
|
||||
|
||||
|
||||
def test_non_default_settings(monkeypatch):
|
||||
@@ -367,3 +368,42 @@ def test_sensitive_settings_mask(monkeypatch: pytest.MonkeyPatch):
|
||||
for setting in sensitive_settings:
|
||||
assert settings[setting] == "*****"
|
||||
assert settings_json[setting] == "*****"
|
||||
|
||||
|
||||
class DetermineSecretsTests:
|
||||
def test_non_production_returns_fixed_key(self, tmp_path: Path):
|
||||
result = determine_secrets(tmp_path, ".secret", production=False)
|
||||
assert result == "shh-secret-test-key"
|
||||
|
||||
def test_generates_secret_when_file_missing(self, tmp_path: Path):
|
||||
result = determine_secrets(tmp_path, ".secret", production=True)
|
||||
assert result
|
||||
assert (tmp_path / ".secret").read_text() == result
|
||||
|
||||
def test_reuses_existing_secret(self, tmp_path: Path):
|
||||
(tmp_path / ".secret").write_text("existing-secret")
|
||||
result = determine_secrets(tmp_path, ".secret", production=True)
|
||||
assert result == "existing-secret"
|
||||
|
||||
def test_regenerates_when_file_is_empty(self, tmp_path: Path):
|
||||
(tmp_path / ".secret").write_text("")
|
||||
result = determine_secrets(tmp_path, ".secret", production=True)
|
||||
assert result
|
||||
assert (tmp_path / ".secret").read_text() == result
|
||||
|
||||
def test_regenerates_when_file_is_whitespace_only(self, tmp_path: Path):
|
||||
(tmp_path / ".secret").write_text(" \n ")
|
||||
result = determine_secrets(tmp_path, ".secret", production=True)
|
||||
assert result
|
||||
assert (tmp_path / ".secret").read_text() == result
|
||||
|
||||
def test_generates_unique_secrets(self, tmp_path: Path):
|
||||
dir_a = tmp_path / "a"
|
||||
dir_b = tmp_path / "b"
|
||||
result_a = determine_secrets(dir_a, ".secret", production=True)
|
||||
result_b = determine_secrets(dir_b, ".secret", production=True)
|
||||
assert result_a != result_b
|
||||
|
||||
def test_no_tmp_file_left_after_write(self, tmp_path: Path):
|
||||
determine_secrets(tmp_path, ".secret", production=True)
|
||||
assert not (tmp_path / ".tmp").exists()
|
||||
|
||||
Reference in New Issue
Block a user